Events
Payload envelope
Every event uses the same envelope. Event-specific fields are indata.
The
delivery_id field matches the X-UgaText-Delivery-ID header.
SMS events
sms.failed webhooks report the reason in error_reason (alongside error_code). GET /sms/status/{id} and cross-border DLR callbacks use failure_reason instead. To handle both, read data.error_reason || data.failure_reason.wallet.topup
Fired as soon as a Mobile Money top-up (MTN Mobile Money, Airtel Money, or M-Pesa) completes and SMS credits are added to your wallet.Configure in the dashboard
1
Open webhook settings
In the dashboard, go to API & Webhooks and open the Webhooks tab.
2
Set your endpoint
Paste your HTTPS destination URL, set a webhook secret, and choose which events to receive.
3
Adjust advanced options
Optionally configure retry policies and payload formats, then save.
4
Test
Use the built-in webhook simulator to send test events to your endpoint.
Manage webhooks with the API
Register a webhook:
An invalid URL returns
400 INVALID_URL.
Request headers
Every webhookPOST from UgaText includes these headers:
All webhook URLs on your account share one account-level signing secret (
whsec_...).Verify signatures
Always verify the signature before trusting the payload.1
Parse the header
Split
X-UgaText-Signature on , to get the timestamp t and the signature v1.2
Build the signed payload
Join the timestamp, a literal period, and the raw, unparsed request body:
3
Compute the digest
Compute an HMAC SHA-256 of that string with your signing secret (
whsec_...), encoded as lowercase hex.4
Compare
Compare your digest with
v1 using a constant-time function such as crypto.timingSafeEqual or hmac.compare_digest. To prevent replay attacks, also reject requests where t is more than 5 minutes (300 seconds) old.
