Webhook Developer Guide

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.

Event Types

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.

Code Samples

Sample code to implement on your Web server, to capture Webhook callbacks:

Request Headers

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

Payload Structure

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
        }
    }
]

Implementing Your Webhook

When you implement your webhook, be aware of the following:

Response Codes

Your 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

Testing and Troubleshooting

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.

The Retry Process

When an invocation fails with a retry-able error, BulkSMS follows this schedule:

  1. First retry: 90 seconds after the failure
  2. Second retry: 3 minutes later
  3. Third retry: 6 minutes later
  4. Fourth retry: 12 minutes later
  5. Subsequent retries: every 15 minutes for up to 2 days

After all retries are exhausted, the message is discarded.

Problem Reports via Email

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.