Webhooks
The platform sends POST requests to your callback URL on key events. Signing is identical to inbound Open API calls.
Configuration
- Admin console: API credentials → callback URL
- Or API:
POST /open-api/v1/webhook/set
{ "callbackUrl": "https://your-server.com/openapi/callback" }Event types
Partner-facing Webhooks expose only 3 eventType values (unlike eSIM Access / Billion inbound notifyType). Many fulfillment/profile changes are aggregated into DELIVERY_UPDATED. The payload matches Query Order; inspect orderStatus, deliveryStatus, and items[].profiles[] for the actual change.
| eventType | Description |
|---|---|
ORDER_PAID | Balance payment succeeded; fulfillment started |
DELIVERY_UPDATED | Delivery or profile state changed (see triggers below). Sent only when that order actually changed |
REFUND_COMPLETED | Refund credited (sync or async Billion after-sale complete) |
Interpreting DELIVERY_UPDATED
The webhook body is a full order snapshot (same as query), not a delta. Use changeHints first:
- Computed by diffing against the last successfully delivered snapshot for the same
orderNo+eventType - First push or no history: inferred vs empty baseline (e.g. new
iccid→ICCID_READY) - Multiple hints may appear in one delivery
- Retries reuse the same hints
See the Chinese Webhook guide for the full changeHints and status enum tables (English summary below).
| changeHints | Meaning |
|---|---|
ICCID_READY / QR_CODE_READY / ACTIVATION_CODE_READY | First time iccid / QR / activation code appears |
DELIVERY_STATUS_CHANGED / ORDER_STATUS_CHANGED / ITEM_STATUS_CHANGED | Order-level status changed |
PROFILE_LIFECYCLE_CHANGED | Profile lifecycleStatus changed (PENDING→DELIVERED→ACTIVATING→ACTIVATED→CANCELLED) |
PLAN_USE_STARTED / PLAN_USE_ENDED | Plan usage started / ended |
USAGE_UPDATED | Cached usage bytes changed |
PROFILE_CANCELLED | Profile cancelled |
ORDER_SNAPSHOT_SYNC | Push with no finer rule matched — refresh full snapshot |
Prefer lifecycleStatus over raw esimStatus / smdpStatus (supplier-specific strings).
DELIVERY_UPDATED triggers (platform internal)
These platform-side changes all emit DELIVERY_UPDATED (there is no separate ESIM_STATUS, DATA_USAGE, etc.):
| Scenario | Typical payload changes |
|---|---|
| ICCID / QR / activation code ready | items[].iccid, qrCodeUrl, activationCode; deliveryStatus → PARTIAL / DELIVERED |
| eSIM install / status | items[].profiles[].esimStatus, smdpStatus |
| Plan usage start / end | items[].profiles[].planUseStatus, planUseStartTime, planUseEndTime |
| Data / validity alerts | items[].profiles[].dataUsageBytes, remainDataBytes, usagePercent |
| Activation / lifecycle | items[].profiles[].activated, lifecycleStatus |
| Profile updates during refund rejection | items[].profiles[].cancelled; credit still via REFUND_COMPLETED |
Not sent as separate events
| Expected scenario | Notes |
|---|---|
REFUNDING in progress | Refund API may return REFUNDING; no webhook until credited — poll query or wait for REFUND_COMPLETED |
| Top-up approved | Account flow; not order webhooks |
| Payment failed at order time | No order row; no webhook |
Delivery policy
- Events are order-scoped; the platform presents a unified order/profile model
- Only actual state changes for that order are pushed; no change means no webhook
- Supported profile fields may vary by package; rely on
items[].profiles[]in the payload
Request format
Headers match inbound API (platform signs with your AppSecret).
Delivery / profile update example:
{
"eventType": "DELIVERY_UPDATED",
"transactionId": "your-transaction-id",
"orderNo": "ORD20260101001",
"orderId": 123456,
"payStatus": "PAID",
"deliveryStatus": "DELIVERED",
"orderStatus": "COMPLETED",
"currency": "USD",
"changeHints": ["ICCID_READY", "DELIVERY_STATUS_CHANGED"],
"items": [
{
"itemNo": "ITEM001",
"iccid": "8901234567890123456",
"profiles": [
{
"iccid": "8901234567890123456",
"esimStatus": "IN_USE",
"planUseStatus": "STARTED"
}
]
}
]
}Refund completed example:
{
"eventType": "REFUND_COMPLETED",
"transactionId": "your-transaction-id",
"orderNo": "ORD20260101001",
"orderId": 123456,
"payStatus": "REFUNDED",
"orderStatus": "REFUNDED",
"refundAmount": 3.50,
"currency": "USD",
"items": []
}See WebhookCallbackPayload in OpenAPI Spec.
Retries
Failed deliveries are retried with backoff. Your endpoint should be idempotent on orderNo + eventType.