Using your Sendo dashboard, you can set up campaign-specific webhooks URLs to listen for incoming messages, message status updates, and recipient optouts. These will be sent as POST requests to the URLs you provide, and they will be resent if the request fails.

If you navigate to the Webhooks tab on a Campaign page, you can see a history of the events that have been sent to your URLs and check for any failures.

As of February 7th, you can configure your webhooks to send events for a subset of the phone numbers attached to your campaign. This can be helpful if you have a testing number.

Authentication

When you create a webhook URL on your dashboard, the system will generate a unique secret token. This token will be sent as a X-Webhook-Token header with each request. You should verify the token to ensure that the request is coming from Sendo.

Retry policy

If our attempt to deliver the POST request to your webhook URL fails with an HTTP response that is not 2XX, we will retry the request up to 6 times with a 60 second delay between each attempt. With each subsequent failure, the wait time will double. If after all attempts the webhook is still not acknowledged, no further attempts will be made.

Please contact us if you are experiencing issues receiving webhook events

message.incoming

Whenever a user sends a message to a phone number associated with a campaign, a POST request will be sent to your provided webhook URL with the following JSON body:

{
  "id": "04165fc8-2b3b-438e-8a33-3e5552c1122d",
  "type": "message.incoming",
  "timestamp": "2023-09-08T00:20:01.439Z",
  "message": {
    "id": "3106592b-ce0c-47e9-9a99-7511db1f8f16",
    "type": "MMS",
    "createdAt": "2023-09-08T00:20:00.849Z",
    "sentAt": "2023-09-08T00:19:56.025Z",
    "direction": "INBOUND",
    "from": "+1234567890",
    "to": "+14159436397",
    "body": "Hello world!",
    "status": "DELIVERED",
    "errorCode": null,
    "errorMessage": null,
    "mediaUrls": ["https://upload.wikimedia.org/wikipedia/commons/dog.jpg"],
    "campaignId": "j4tYqwn3"
  }
}
Please contact us if you think you have issues receiving incoming messages

message.status

Whenever the status of a sent message changes (see full list below), a POST request will be sent to your provided webhook URL with the following JSON body:

{
  "id": "a02d7de8-8405-47e8-acc5-6af147c67e24",
  "type": "message.status",
  "timestamp": "2023-09-08T00:20:01.439Z",
  "message": {
    "id": "34f9e131-6411-4d53-9fd5-5c75cc40778c",
    "type": "SMS",
    "createdAt": "2023-09-08T00:20:00.849Z",
    "sentAt": "2023-09-08T00:19:56.025Z",
    "direction": "OUTBOUND",
    "from": "+14159436397",
    "to": "+1234567890",
    "body": "Hello world!",
    "status": "DELIVERED",
    "errorCode": null,
    "errorMessage": null,
    "mediaUrls": [],
    "metadata": {
      "customId": "123456789"
    }
    "campaignId": "j4tYqwn3"
  }
}
You can store custom metadata in the metadata field (learn more)

Statuses

StatusDescription
CREATEDThe message has been created
QUEUEDThe message is queued for sending
SCHEDULEDThe message is scheduled for sending
SENTThe message has been sent
DELIVEREDThe message has been delivered
READThe message has been opened
FAILEDThe message send has failed
EXPIREDThe send has failed. Contact support
See a full list of message errors here for the FAILED status
Often MMS messages will stay as SENT and are never marked as DELIVERED

recipient.optout

When a recipient texts STOP or another keyword to unsubscribe from messages, a POST request will be sent to your webhook URL with the following JSON body:

{
  "id": "9c78197b-d20c-42c3-9f7d-f04cf0fac3be",
  "type": "recipient.optout",
  "timestamp": "2023-09-08T00:20:01.439Z",
  "message": {
    "id": "c467664f-840c-498a-ab9f-eedd8d7e73e1",
    "type": "SMS",
    "createdAt": "2023-09-08T00:20:00.849Z",
    "sentAt": "2023-09-08T00:19:56.025Z",
    "direction": "INBOUND",
    "from": "+1234567890", // The number opting out
    "to": "+14159436397",
    "body": "STOP",
    "status": "DELIVERED",
    "errorCode": null,
    "errorMessage": null,
    "mediaUrls": [],
    "campaignId": "j4tYqwn3"
  }
}
These opt-out texts will also be sent as message.incoming events