Webhooks
How top-up status changes are surfaced - polling, email notifications, and the planned webhook events
Outbound client webhooks for top-ups are not yet wired. Voucher orders already fire order.delivered / order.partially_delivered / order.failed / order.cancelled events (plus wallet.credited / wallet.debited) to your registered webhook URL, but the equivalent topup.* events have not yet been rolled out. Until they ship, use the two patterns below.
How to Track Top-Up Status Today
1. Poll the order endpoint
GET /api/v1/topups/orders/:id refreshes the latest status on each call for in-flight orders. A reasonable poll loop:
# Pseudo-shell: poll every 5s for the first minute, then 30s for a few minutes
# An order that's still PENDING after that is Octopus Cards retrying transient
# fulfilment issues — stop foreground polling and lean on notifications.
delay=5
elapsed=0
while [ "$elapsed" -lt 660 ]; do
status=$(curl -s "$HOST/api/v1/topups/orders/$ORDER_ID" \
-H "Authorization: Bearer $TOKEN" | jq -r '.data.status')
case "$status" in
DELIVERED|FAILED|CANCELLED) echo "Terminal: $status"; break ;;
esac
sleep $delay
elapsed=$((elapsed + delay))
[ "$elapsed" -ge 60 ] && delay=30
doneTop-ups typically resolve within 5–30 seconds. The retry cron handles slower fulfilment paths in the background, so your poll will eventually see a terminal status even if the first attempt hung.
2. Attach a notification email
PATCH /api/v1/topups/orders/:id/notification-email registers an email address that is sent a templated receipt on terminal transitions:
DELIVERED→ success email with the variant name and referenceFAILED→ failure email with the customer-safefailure_reasonCANCELLED→ cancellation email with refund confirmation
Email notifications fire at the same terminal points where webhook events will fire once they ship. They are server-driven (no polling needed) but only useful for end-user-facing flows where you actually have a customer email.
Planned Webhook Events
When outbound topup webhooks land, the envelope will match the voucher webhook shape (see Voucher Webhooks for the established pattern):
{
"id": "evt_topup_abc123",
"type": "topup.delivered",
"created_at": "2026-05-15T14:31:12Z",
"data": {
"id": 9123456,
"client_reference": "RECHARGE_REQ_4391",
"status": "DELIVERED",
"product_name": "PUBG Mobile UC",
"variant_name": "325 UC",
"amount": 4.7405,
"currency": "USD",
"completed_at": "2026-05-15T14:31:12Z"
}
}Expected event types:
| Event | Trigger |
|---|---|
topup.delivered | Order moved to DELIVERED. Final. |
topup.failed | Order moved to FAILED. Wallet auto-refunded. Final. failure_code / failure_reason / is_user_fixable will be in data. |
topup.cancelled | Order cancelled administratively. Wallet refunded. Final. |
In-flight sub-statuses will not fire webhooks — events only fire at terminal transitions. This matches the voucher webhook contract.
For shared HMAC verification mechanics, see Signature Verification.