Webhook
VTUAgent notifies your server when an airtime or data purchase changes state, so you don’t have to poll.
Register your endpoint
One URL per account; calling again replaces it. Retrieve the current value with GET /v1/webhook/get. Your endpoint must be a publicly reachable absolute URL — use HTTPS.
Delivery
For each event VTUAgent sends a single POST to your URL with Content-Type: application/json and a 10-second timeout.
- No retries. If your endpoint is down or responds slowly, the event is not resent. If you miss a delivery, fetch the outcome with
POST /v1/transaction/status. - No
Authorizationheader. Authenticity is carried by thehashfield in the body (see below). - Respond with HTTP
200as quickly as possible and do your own processing afterwards.
Events
Cable TV and electricity purchases do not emit webhooks. Their responses are synchronous; if one returns 202 pending, poll POST /v1/transaction/status.
Payload
The body always contains exactly these eight fields:
Verifying the hash
Every webhook carries a SHA-256 digest of your API key and the transaction reference, joined with a colon. Because only VTUAgent and you know the API key, a matching digest confirms the webhook came from VTUAgent and refers to a transaction on your account.
Recompute it and compare to the received value with a constant-time comparison. Reject the request if they differ.
If you have more than one active API key, the hash is computed with the most recently created one — update your webhook handler when you rotate keys.
Handling duplicates
transaction.requery fires on every call to the status endpoint, so you may receive the same reference more than once, and a pending event is normally followed by success or failed. Key your processing on reference and apply state transitions idempotently — never move a transaction from success back to pending, and never fulfil the same reference twice.
Checklist
- Register an HTTPS URL with
POST /v1/webhook/set. - On each delivery: parse the JSON, verify
hash, respond200immediately. - Process asynchronously, matching
referenceto your own records. - Handle repeats idempotently; there are no retries, so use
POST /v1/transaction/statusto recover any missed event.
