Real-Time Delivery Notifications
Push-based webhooks deliver delivery receipts and inbound messages to your endpoint the moment they occur — no polling required. Signed, retried, and built for production reliability.
Real-Time Events for Every Message
Delivery Receipt Webhooks
Fired when a message delivery status changes — on delivery, failure, or expiry. Provides real-time confirmation that a message has reached (or failed to reach) the recipient.
- Delivered confirmation
- Failed delivery notification
- Expired message notification
- Carrier-level status detail
MO Message Webhooks
Fired when an inbound message (MO) is received on your virtual number or shared shortcode. Delivers the sender's number, message content, and timestamp to your endpoint.
- Inbound SMS to your number
- Sender number and content
- Received timestamp
- Network identifier
Retry Logic
If your webhook endpoint is unreachable or returns a non-2xx status, our system retries delivery using exponential backoff — ensuring you never permanently lose a webhook event.
- Automatic retry on failure
- Exponential backoff (15s, 1m, 5m, 30m, 2h)
- Up to 5 retry attempts
- Failed event logging
Signature Verification
Every webhook request is signed with an HMAC-SHA256 signature using your webhook secret. Verify the signature on your server to confirm the request genuinely originated from SBS TELECOM.
- HMAC-SHA256 request signing
- Signature in X-SBS-Signature header
- Timestamp in X-SBS-Timestamp
- Replay attack prevention
Webhook Payload Structure
All webhooks are delivered as HTTP POST requests with a JSON body. The payload structure is consistent across event types, with an event field identifying the type.
eventdelivery_receiptmessageIdYour message ID from submittoDestination number (E.164)fromSender ID usedstatusDELIVERED | FAILED | EXPIRED | UNDELIVERABLEerrorCodeCarrier error code (on failure)deliveredAtISO 8601 delivery timestampnetworkCarrier network identifier
POST https://yourapp.com/webhooks/sms
Content-Type: application/json
X-SBS-Signature: sha256=abc123...
X-SBS-Timestamp: 1711101735
{
"event": "delivery_receipt",
"messageId": "msg_01HX8K2P4NQR9VTZE",
"to": "+447911123456",
"from": "SBSTELECOM",
"status": "DELIVERED",
"errorCode": null,
"deliveredAt": "2025-03-22T10:42:16Z",
"network": "EE-UK",
"latency": 0.82
}{
"event": "mo_message",
"messageId": "mo_01HX9M3Q6PRW0XUZB",
"from": "+447911654321",
"to": "74100",
"text": "STOP",
"receivedAt": "2025-03-22T10:45:01Z",
"network": "Vodafone-UK"
}Verifying Webhook Signatures
Every webhook request includes an HMAC-SHA256 signature computed from the request timestamp and body, using your webhook signing secret. Always verify this signature before processing the payload.
Reject any request where signature verification fails — it may be a forged or replayed request. Also check that the timestamp in the X-SBS-Timestamp header is within an acceptable window (we recommend 5 minutes) to prevent replay attacks.
- Retrieve your signing secret from the portal
- Compute HMAC-SHA256 of timestamp.body
- Compare with X-SBS-Signature header value
- Reject if signatures do not match
- Reject if timestamp is outside 5-minute window
- Return HTTP 200 only after successful verification
import hmac
import hashlib
import time
def verify_webhook(
payload: bytes,
signature_header: str,
timestamp_header: str,
secret: str
) -> bool:
# Check timestamp recency (5 min window)
ts = int(timestamp_header)
if abs(time.time() - ts) > 300:
return False
# Compute expected signature
msg = f"{timestamp_header}.{payload.decode()}"
expected = hmac.new(
secret.encode(),
msg.encode(),
hashlib.sha256
).hexdigest()
# Compare signatures securely
received = signature_header.replace('sha256=', '')
return hmac.compare_digest(expected, received)Ready to Implement Webhooks?.
Get API credentials and a webhook signing secret to start receiving real-time delivery notifications.