A webhook is a URL that the BulkSMS system calls to notify you about your messages. You can manage webhooks via the Webhooks API or the Web App.
When BulkSMS invokes your webhook, the X-BulkSMS-Event header indicates the type of event:
| Event | Description |
|---|---|
incoming-message |
A mobile originating (MO) message was received |
status-report |
A status update is available for a sent (MT) message |
To receive both event types you need to create two webhooks — one with triggerScope set to SENT (for status reports) and one set to RECEIVED (for incoming messages). You can use the same URL for both.
Sample code to implement on your Web server, to capture Webhook callbacks:
BulkSMS sends the following headers with each webhook invocation:
POST /your-webhook-path HTTP/1.1
X-BulkSMS-Event: incoming-message
X-BulkSMS-Delivery: 1
X-BulkSMS-Delivery-Attempt: 1
X-BulkSMS-Webhook-Id: 12345
Content-Type: application/json
User-Agent: BulkSMS Invoker
| Header | Description |
|---|---|
X-BulkSMS-Event |
The event type (incoming-message or status-report) |
X-BulkSMS-Delivery |
Delivery identifier |
X-BulkSMS-Delivery-Attempt |
The attempt number (increments on retries) |
X-BulkSMS-Webhook-Id |
The ID of the webhook that triggered this call |
The request body is a JSON array of message objects. The structure is the same as the output from the List Messages API call.
[
{
"id": "312123871239124",
"from": {
"type": "INTERNATIONAL",
"address": "+27000000000"
},
"to": {
"type": "INTERNATIONAL",
"address": "+44000000000"
},
"body": {
"value": "Hello World",
"encoding": {
"type": "TEXT"
}
},
"protocolId": {
"name": "IMPLICIT",
"value": 0
},
"messageClass": {
"name": "CLASS_2",
"value": 2
},
"userSuppliedId": "abcd1234",
"submission": {
"id": "564568749793",
"date": "2014-06-01T12:15:00Z",
"interface": "https://api.bulksms.com/v1/messages"
},
"status": {
"condition": "SENT",
"date": "2014-06-01T13:10:00Z",
"cause": "Submitted to upstream provider",
"final": false
}
}
]
When you implement your webhook, be aware of the following:
POST requests containing a JSON array of messages.[]).https://www.example.com/hook.php?secret=pass763265wordhttps://www.example.com:8321/hook.phpYour webhook must respond with an appropriate HTTP status code:
| Status Code | Meaning |
|---|---|
1xx, 2xx (e.g. 200 OK, 204 No Content) |
Success — the message was processed and the webhook is ready for more |
4xx (e.g. 400 Bad Request) |
Permanent failure — the message will be discarded, but future messages will still be delivered |
429 Too Many Requests |
Rate limiting — BulkSMS will slow down and retry |
503 Service Unavailable |
Temporary problem — BulkSMS will retry (you can include a Retry-After header) |
410 Gone |
Cancellation — BulkSMS will stop invoking this webhook entirely |
| Any other status code | Temporary problem — BulkSMS will retry |
Examples:
HTTP/1.0 200 OK
Content-Type: text/plain
OK
HTTP/1.0 503 Service Unavailable
Retry-After: 120
Use curl to test your webhook before registering it. The command below simulates how BulkSMS invokes your endpoint — it must return 200 for your URL to be accepted:
curl -i -X POST 'YOUR_URL_HERE' \
--header 'Content-Type: application/json' \
--header 'User-Agent: BulkSMS Invoker' \
--data-raw '[]'
Once you get 200 for an empty array, test with a real payload by adding JSON message objects between the square brackets.
After your webhook is registered, you can send a message to 1111111 for an end-to-end test. Delivery to this test number will fail (expected), but your webhook will still be invoked. There are no charges for messages to this number.
When an invocation fails with a retry-able error, BulkSMS follows this schedule:
After all retries are exhausted, the message is discarded.
You are strongly advised to provide a contactEmailAddress when you register your webhook. BulkSMS will send email notifications when problems occur:
To prevent inbox flooding, each type of notice is sent at most once per 24-hour period.