BDApps Integration Guide
AppsPro is a subscription management platform built on top of the Dialog Axiata BDApps telecom API. It handles subscriber lifecycle, OTP-based checkout, SMS delivery, charging, and webhook forwarding — so you can focus on building your app.
How it works
Quickstart
1. Register & Create an App
Sign up on the AppsPro dashboard, then create a new app. In the BDApps settings, enter your applicationId and password from the BDApps TAP portal (developer.bdapps.com).
2. Get SDK Credentials
After creating your app, go to the Credentials tab. You'll get:
client_idUsername for SDK Basic Auth
client_secretPassword for SDK Basic Auth (shown once)
public_keyFor unauthenticated app info lookup
signing_keyFor webhook signature verification
3. Make Your First API Call
Verify a subscriber using Basic Auth with your SDK credentials:
curl https://api.appspro.dev/api/v1/sdk/verify/tel:8801712345678 \
-u "your_client_id:your_client_secret"SDK Guide
Authentication
SDK endpoints use HTTP Basic Auth. Encode client_id:client_secret as a Base64 string and pass it in the Authorization header.
Authorization: Basic base64(client_id:client_secret)Keep credentials secure
Never expose your client_secret in client-side code. SDK calls should always be made from your server.
Verify Subscription
Check whether a subscriber has an active subscription. Pass either the BDApps subscriber ID (e.g. tel:8801XXXXXXXXX) or the local AppsPro UUID.
/api/v1/sdk/verify/{subscriber_id}Returns subscription validity, subscriber details, and reason if invalid.
Response
{
"valid": true,
"subscriber": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"bdapps_subscriber_id": "tel:8801712345678",
"phone_masked": "01712***678",
"status": "active",
"subscription_type": "bdapps",
"frequency": "daily",
"subscribed_at": "2026-05-11T10:30:00Z",
"cancelled_at": null,
"created_at": "2026-05-11T10:30:00Z"
},
"reason": null
}List Subscribers
Paginated list of all subscribers for your app. Filter by status.
/api/v1/sdk/subscribers?page=1&limit=20&status=activeReturns paginated subscriber list with total count.
{
"subscribers": [
{
"id": "...",
"bdapps_subscriber_id": "tel:8801712345678",
"phone_masked": "01712***678",
"status": "active",
"frequency": "daily",
"subscribed_at": "2026-05-11T10:30:00Z"
}
],
"total": 42,
"page": 1,
"limit": 20
}App Info (Public)
Retrieve public metadata for your app. No authentication required — only the public_key.
/api/v1/sdk/app-info?public_key=xxxReturns app name, description, category, pricing model, and icon URL.No Auth
Checkout Flow
Hosted Checkout Page
AppsPro provides a hosted checkout page for end-user subscriptions. Share or embed the checkout URL in your app. Users subscribe via OTP — no integration work needed on your end.
https://yourdomain.com/s/{client_id}Flow
- User visits
/s/{client_id}— sees your app info - User enters their Bangladeshi mobile number
- OTP is sent via BDApps SMS
- User verifies OTP on the checkout page
- Subscription is created — user is redirected to your configured
checkout_redirect_url
Checkout Endpoints
These endpoints power the hosted checkout page. No authentication required.
/s/{client_id}/infoGet app info for the checkout UI (name, description, icon, pricing).No Auth
/s/{client_id}/otp/requestSend OTP to a phone number. Rate limited to 10/hour per phone.No Auth
// POST body
{ "phone": "01712345678" }
// Response
{
"reference_no": "bdapps_ref_abc123",
"status_code": "S1000",
"status_detail": "Success"
}/s/{client_id}/otp/verifyVerify OTP and create the subscription.No Auth
// POST body
{
"reference_no": "bdapps_ref_abc123",
"otp": "1234"
}
// Response
{
"subscription_status": "REGISTERED",
"subscriber_id": "tel:8801712345678",
"local_subscriber_id": "550e8400-...",
"redirect_url": "https://yourapp.com/welcome",
"status_code": "S1000",
"status_detail": "Success"
}Phone number formats
Accepts 01XXXXXXXXX, 8801XXXXXXXXX, or +8801XXXXXXXXX — with or without spaces and dashes.
Webhooks
Configure a webhook URL in your app settings to receive real-time events from BDApps, forwarded through AppsPro.
Event Types
subscriber.createdA new subscriber registered via OTPsubscriber.cancelledA subscriber unsubscribedsms.receivedIncoming SMS message from a subscriberussd.receivedIncoming USSD request from a subscriberSubscription Event Payload
POST https://your-server.com/webhooks/texionapps
Headers:
Content-Type: application/json
X-Event-Type: subscriber.created
X-Signature: sha256=abc123...
Body:
{
"event": "subscriber.created",
"data": {
"timeStamp": "2026-05-11T10:30:00Z",
"applicationId": "BDAPPS_123",
"subscriberId": "tel:8801712345678",
"status": "REGISTERED",
"frequency": "daily",
"internal_subscriber_id": "550e8400-..."
}
}SMS Event Payload
{
"event": "sms.received",
"data": {
"applicationId": "BDAPPS_123",
"sourceAddress": "tel:8801712345678",
"message": "Hello from subscriber",
"requestId": "req_xyz",
"encoding": "0"
}
}Signature Verification
Every webhook request includes an X-Signature header containing an HMAC-SHA256 signature of the request body, signed with your app's signing_key. Always verify this signature before processing the payload.
import hmac, hashlib
def verify_signature(body: bytes, signature: str, signing_key: str) -> bool:
expected = hmac.new(
signing_key.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)BDApps Operations
These authenticated endpoints let you interact with BDApps directly through your AppsPro app. All require JWT authentication and app ownership.
SMS
/apps/{app_id}/bdapps/smsSend SMS to specific phone numbers.
// POST body
{
"destination": ["01712345678", "01898765432"],
"message": "Hello from your app!",
"source_address": null
}
// Response
{
"sent_count": 2,
"status_code": "S1000",
"status_detail": "Success"
}/apps/{app_id}/bdapps/sms/broadcastSend SMS to all active subscribers.
// POST body
{ "message": "Daily update for all subscribers" }
// Response
{ "sent_count": 150, "status_code": "S1000", "status_detail": "Success" }Charging (CAAS)
Content-as-a-Service endpoints for charging subscribers and querying balances.
/apps/{app_id}/bdapps/debitCharge a subscriber's mobile account (BDT).
// POST body
{
"phone": "01712345678",
"amount": "10.00",
"external_trx_id": "txn_abc123"
}
// Response
{ "status_code": "S1000", "status_detail": "Success" }/apps/{app_id}/bdapps/balance/{phone}Query a subscriber's chargeable balance.
/apps/{app_id}/bdapps/base-sizeGet total subscriber base size for the app.
Subscription Management
/apps/{app_id}/bdapps/status/{phone}Check subscription status for a phone number.
/apps/{app_id}/bdapps/subscribeManually subscribe a phone number.
/apps/{app_id}/bdapps/unsubscribeManually unsubscribe a phone number.
/apps/{app_id}/bdapps/test-connectionTest that your BDApps credentials are valid.
Manual OTP (from Dashboard)
/apps/{app_id}/bdapps/otp/requestRequest OTP for a phone number.
/apps/{app_id}/bdapps/otp/verifyVerify OTP and create subscription.
Code Examples
Verify Subscription (Python)
import requests
response = requests.get(
"https://api.appspro.dev/api/v1/sdk/verify/tel:8801712345678",
auth=("your_client_id", "your_client_secret"),
)
data = response.json()
if data["valid"]:
print(f"Active subscriber: {data['subscriber']['id']}")
else:
print(f"Invalid: {data['reason']}")Verify Subscription (JavaScript)
const credentials = btoa(`${clientId}:${clientSecret}`);
const res = await fetch(
"https://api.appspro.dev/api/v1/sdk/verify/tel:8801712345678",
{
headers: {
Authorization: `Basic ${credentials}`,
},
}
);
const data = await res.json();
if (data.valid) {
console.log("Active subscriber:", data.subscriber.id);
} else {
console.log("Invalid:", data.reason);
}Handle Webhook (Node.js / Express)
import crypto from "crypto";
import express from "express";
const app = express();
app.use(express.raw({ type: "application/json" }));
app.post("/webhooks/texionapps", (req, res) => {
const signature = req.headers["x-signature"];
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.SIGNING_KEY)
.update(req.body)
.digest("hex");
if (!crypto.timingSafeEqual(
Buffer.from(signature), Buffer.from(expected)
)) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body);
switch (payload.event) {
case "subscriber.created":
console.log("New subscriber:", payload.data.subscriberId);
break;
case "subscriber.cancelled":
console.log("Unsubscribed:", payload.data.subscriberId);
break;
case "sms.received":
console.log("SMS from:", payload.data.sourceAddress);
break;
}
res.sendStatus(200);
});Send SMS (cURL)
curl -X POST https://api.appspro.dev/apps/{app_id}/bdapps/sms \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination": ["01712345678"],
"message": "Hello from your app!"
}'BDApps Status Codes
S1000SuccessE1312Invalid phone numberE1325Invalid OTPE403Insufficient permissionsE404Resource not foundAll BDApps responses include status_code, status_detail, and a raw field with the full BDApps response.
WebSDK
Overview
The AppsPro WebSDK lets you embed a subscription widget directly in your website or mobile app without redirecting users to a separate page. The widget is injected as plain HTML into your container — no iframe, no postMessage. This makes it reliable in all mobile WebViews (Android/iOS) as well as standard browsers.
How it works
Installation & Usage
1. Include the script
<script src="https://appspro.dev/sdk/v1/texionapps.js"></script>2. Add a container and initialize
<!-- In your HTML -->
<div id="subscribe-box"></div>
<script>
const sdk = AppsPro('YOUR_PUBLIC_KEY');
const el = sdk.elements.create('subscribe', {
buttonText: 'Subscribe Now',
buttonColor: '#6366f1', // any CSS hex color
theme: 'dark', // 'dark' | 'light'
locale: 'en',
compact: false, // smaller padding
hideHeader: false, // hide app name header
});
el.mount('#subscribe-box');
el.on('ready', () => console.log('Widget ready'));
el.on('success', (data) => {
console.log('Subscribed!', data.subscriberId);
// Verify on your server:
// GET /api/v1/sdk/verify/{data.subscriberId}
});
el.on('error', (err) => console.error('Error:', err.message));
</script>Options reference
sdk.elements.create('subscribe', {
buttonText: string, // default: 'Subscribe Now'
buttonColor: string, // default: '#6366f1'
theme: string, // 'dark' | 'light', default: 'dark'
locale: string, // default: 'en'
compact: boolean, // default: false
hideHeader: boolean, // default: false
borderRadius: string, // default: '12px'
baseUrl: string, // override API base (dev only)
})Events
| Event | Payload | Description |
|---|---|---|
| ready | {} | Widget has rendered in the DOM |
| success | { subscriberId, localSubscriberId, redirectUrl } | User subscribed successfully |
| error | { message } | An error occurred in the flow |
| otp-sent | { phone } | OTP was sent to the phone |
| payment-redirect | { url } | Redirect URL is available |
| cancel | {} | User cancelled the flow |
Flutter / WebView Integration
For Flutter apps, load the WebSDK inside a WebView using the webview_flutter package. The SDK automatically calls a JavaScript channel named AppsPro with every event, so no extra wiring is needed on the JS side.
import 'dart:convert';
import 'package:webview_flutter/webview_flutter.dart';
class SubscribeWebView extends StatefulWidget {
final String publicKey;
const SubscribeWebView({required this.publicKey, super.key});
@override
State<SubscribeWebView> createState() => _SubscribeWebViewState();
}
class _SubscribeWebViewState extends State<SubscribeWebView> {
late final WebViewController _controller;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'AppsPro', // SDK calls window.AppsPro.postMessage() automatically
onMessageReceived: (msg) {
final data = jsonDecode(msg.message) as Map<String, dynamic>;
if (data['type'] == 'success') {
final subscriberId = data['data']['subscriberId'];
Navigator.pop(context, subscriberId);
}
},
)
..loadHtmlString(_buildHtml());
}
String _buildHtml() => """
<!DOCTYPE html><html><head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://appspro.dev/sdk/v1/texionapps.js"></script>
</head><body style="margin:0;background:#0f0f13">
<div id="sub"></div>
<script>
const sdk = AppsPro('${widget.publicKey}');
const el = sdk.elements.create('subscribe', { hideHeader: true });
el.mount('#sub');
// Events fire automatically to the AppsPro JavascriptChannel
</script></body></html>""";
@override
Widget build(BuildContext context) => WebViewWidget(controller: _controller);
}AI Agent / LLM Docs
Copy the markdown below and paste it into your AI assistant (Claude, ChatGPT, Cursor, etc.) to give it full context about the AppsPro API.
# AppsPro — BDApps Integration API Reference
Base URL: https://api.appspro.dev
Auth: Bearer <access_token> in Authorization header
All BDApps endpoints require:
- A registered AppsPro account
- An app created in the dashboard with BDApps credentials configured (base_uri, client_id, password)
---
## BDApps Operations
All endpoints: POST/GET /apps/{id}/bdapps/...
Replace {id} with your AppsPro app's numeric ID.
### SMS
POST /apps/{id}/bdapps/sms
Body: { "phone": "01XXXXXXXXX", "message": "Your text here" }
### Subscriber Balance
GET /apps/{id}/bdapps/balance/{phone}
Returns: { status_code, status_detail, chargeable_balance, raw }
### Direct Debit (Charge subscriber)
POST /apps/{id}/bdapps/debit
Body: { "phone": "01XXXXXXXXX", "amount": 5.00, "ext_trx_id": "unique-txn-id" }
Returns: { status_code, status_detail, internal_trx_id, reference_id, timestamp, raw }
### Subscribe
POST /apps/{id}/bdapps/subscribe/{phone}
Subscribes the phone number to your service.
### Unsubscribe
POST /apps/{id}/bdapps/unsubscribe/{phone}
Unsubscribes the phone number from your service.
### Subscription Status
GET /apps/{id}/bdapps/status/{phone}
Returns current subscription status for the number.
### OTP — Request
POST /apps/{id}/bdapps/otp/request
Body: { "phone": "01XXXXXXXXX" }
Returns: { status_code, status_detail, reference_no, raw }
### OTP — Verify
POST /apps/{id}/bdapps/otp/verify
Body: { "reference_no": "...", "otp": "1234" }
Returns: { status_code, status_detail, raw }
### USSD
POST /apps/{id}/bdapps/ussd
Body: { "phone": "01XXXXXXXXX", "message": "text", "session_id": "optional", "type": "optional" }
### Subscriber Base Size
GET /apps/{id}/bdapps/base-size
Returns total subscriber count for the service.
### Test Credentials
POST /apps/{id}/bdapps/test
Validates that the stored BDApps credentials are working.
---
## BDApps Documents
GET /apps/{id}/documents
— List available documents for the app
GET /apps/{id}/documents/bank-verification
— Generate bank earning verification HTML document
GET /apps/{id}/documents/service-faq?username=&password=&service_name=&service_id=&operator=
— Generate BDApps service FAQ HTML document
---
## Response Format
All BDApps operation responses:
{
"status_code": "S1000", // "S1000" = success; any other = failure
"status_detail": "Success",
"raw": { ... } // full BDApps API response
}
Error responses: HTTP 4xx with { "detail": "error message" }
---
## Notes
- Phone numbers must be Bangladeshi format: 01XXXXXXXXX (Robi/Airtel numbers for BDApps)
- ext_trx_id for debit must be unique per transaction
- BDApps credentials (base_uri, client_id, password) are set per-app in the AppsPro dashboard under App Settings
- All requests require a valid Bearer token from POST /auth/login → access_token