Webhooks
Webhooks notify your system of SMS events in real-time. When an event occurs, we send an HTTP POST request to your configured endpoint with JSON data describing the event.
Supported Events
Section titled “Supported Events”| Event Type | Description |
|---|---|
| SMS Delivery Receipt | Triggered when the delivery status of an outbound SMS changes (delivered, failed, expired, etc.) |
| Inbound SMS | Triggered when an SMS is received on your dedicated virtual number |
Configuration
Section titled “Configuration”To configure webhooks, navigate to Settings → Webhooks in your workspace and add your endpoint URL. You can:
- Enable specific event types for each endpoint
- Add an optional secret key for HMAC signature validation
- Add a description to help identify the endpoint
Webhook Format
Section titled “Webhook Format”All webhooks are sent as HTTP POST requests with a JSON payload wrapped in a standard envelope.
Envelope Structure
Section titled “Envelope Structure”JSON Data
Example Envelope
Section titled “Example Envelope”{ "id": "evt_abc123", "timestamp": "2025-01-15T10:30:00Z", "workspaceId": "ws_xyz789", "eventType": 1, "data": { // Event-specific payload }}SMS Delivery Receipt
Section titled “SMS Delivery Receipt”Sent when the delivery status of an outbound SMS changes. Use this to track whether messages were successfully delivered to recipients.
Payload
Section titled “Payload”data Object
Example Payload
Section titled “Example Payload”{ "id": "evt_dr_123456", "timestamp": "2025-01-15T10:30:00Z", "workspaceId": "ws_xyz789", "eventType": 1, "data": { "messageId": "12345678", "clientReference": "order-confirmation-456", "deliveryStatus": "Delivered", "errorCode": null, "processedAt": "2025-01-15T10:29:55Z", "deliveredAt": "2025-01-15T10:30:00Z" }}Delivery Status Values
Section titled “Delivery Status Values”| Status | Final | Description |
|---|---|---|
Queued | No | Message is queued for sending |
Dispatched | No | Message has been sent to the carrier |
Delivered | Yes | Message was successfully delivered to the recipient |
Failed | Yes | Message delivery failed permanently |
Expired | Yes | Message expired before delivery (carrier timeout) |
Rejected | Yes | Message was rejected by the carrier |
Cancelled | Yes | Message was cancelled before delivery |
Deleted | Yes | Message was deleted |
Unknown | No | Status could not be determined |
Error Codes
Section titled “Error Codes”When deliveryStatus is Failed or Rejected, the errorCode field provides additional details.
| Code | Name | Description |
|---|---|---|
400 | Queued | Message is still queued |
401 | Dispatched | Message is dispatched |
402 | MessageUnroutable | No route available for this destination |
403 | InternalError | An internal error occurred |
404 | TemporaryDeliveryFailure | Temporary delivery failure - may retry |
405 | UnmatchedParameter | Invalid parameter in request |
406 | InternalExpiry | Message expired internally |
407 | Cancelled | Message was cancelled |
408 | InternalReject | Message rejected internally |
410 | UnmatchedDefaultOriginator | Sender ID not valid for destination |
411 | ExceededPartsLimit | Message exceeded maximum parts limit |
412 | UnprovisionedRegion | Destination region not supported |
413 | Blocked | Message blocked by carrier or filter |
Inbound SMS
Section titled “Inbound SMS”Sent when an SMS is received on your dedicated virtual number. This allows you to receive replies and implement two-way SMS conversations.
Payload
Section titled “Payload”data Object
Example Payload
Section titled “Example Payload”{ "id": "evt_in_789012", "timestamp": "2025-01-15T14:22:30Z", "workspaceId": "ws_xyz789", "eventType": 2, "data": { "messageId": "inb_987654", "inboundNumber": "+447700900100", "sender": "+447700900123", "body": "Yes, please confirm my appointment", "receivedAt": "2025-01-15T14:22:30Z" }}Security
Section titled “Security”HMAC Signature Validation
Section titled “HMAC Signature Validation”If you configure a secret key for your webhook endpoint, we include an HMAC-SHA256 signature that you should validate to ensure the request is authentic.
Headers
Section titled “Headers”| Header | Description |
|---|---|
X-Webhook-Signature | Base64-encoded HMAC-SHA256 signature |
X-Webhook-Timestamp | Unix timestamp (seconds) when the webhook was sent |
Signature Computation
Section titled “Signature Computation”The signature is computed as:
HMAC-SHA256(secret, timestamp + "." + payload)Where:
secretis your configured webhook secrettimestampis the value fromX-Webhook-Timestamppayloadis the raw JSON request body
Validation Example
Section titled “Validation Example”using System.Security.Cryptography;using System.Text;
public bool ValidateWebhookSignature( string payload, string signature, string timestamp, string secret){ var signatureData = $"{timestamp}.{payload}"; using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(signatureData)); var expectedSignature = Convert.ToBase64String(hash);
return signature == expectedSignature;}const crypto = require('crypto');
function validateWebhookSignature(payload, signature, timestamp, secret) { const signatureData = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signatureData) .digest('base64');
return signature === expectedSignature;}function validateWebhookSignature($payload, $signature, $timestamp, $secret) { $signatureData = $timestamp . '.' . $payload; $expectedSignature = base64_encode( hash_hmac('sha256', $signatureData, $secret, true) );
return hash_equals($signature, $expectedSignature);}Retry Behaviour
Section titled “Retry Behaviour”If your endpoint returns a non-2xx response or times out, we will retry delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 5 minutes |
| 3 | 15 minutes |
| 4 | 1 hour |
| 5 | 4 hours |
| 6 | 8 hours |
| 7 | 12 hours |
After 5 consecutive failures, the webhook endpoint is automatically disabled to prevent further failed deliveries. You can re-enable it from the webhook settings page once your endpoint is healthy.
Best Practices
Section titled “Best Practices”-
Respond quickly - Return a 2xx response as soon as possible. Process webhook data asynchronously if needed.
-
Handle duplicates - In rare cases, you may receive the same webhook more than once. Use the
idfield to deduplicate. -
Validate signatures - Always validate the HMAC signature when a secret is configured to ensure requests are authentic.
-
Use HTTPS - Always use HTTPS endpoints to ensure webhook data is encrypted in transit.
-
Monitor failures - Check your webhook settings regularly to ensure endpoints haven’t been auto-disabled due to failures.