Skip to content

When a carrier returns a delivery report, we POST a JSON payload to your delivery_url:

POST https://your-server.com/webhook/delivery
Content-Type: application/json
User-Agent: 23Telecom-Webhooks/1.0
Example payload
{
"message_id": "api_42_1743667200123456789_a3f8b2c1d9e45f67",
"recipient": "+14155551234",
"sender_id": "MyApp",
"status": "DELIVRD",
"status_code": "000",
"num_parts": 1,
"cost": 0.0085,
"timestamp": "2026-02-13T10:30:04Z"
}

Your server must respond with HTTP 2xx within 5 seconds. Anything else triggers automatic retries: up to 3 attempts total, with backoff delays of 10s and 30s. Every attempt is logged — see webhook logs.

Choose fields when configuring the webhook. Defaults: message_id, recipient, sender_id, status, status_code, num_parts, cost, timestamp.

FieldDescription
message_idYour message ID (from the send response)
telecom_message_idCarrier-assigned ID (deprecated — use message_id)
recipientDestination phone number
sender_idSender ID used
statusDELIVRD, UNDELIV, REJECTD, EXPIRED, UNKNOWN
status_codeCarrier-specific status code
num_partsSMS segment count
costActual cost from the carrier (may be 0 on free routes)
timestampDelivery time, ISO 8601 UTC
workspace_idOpt-in — see workspaces

Signature verification shown below is optional but recommended — set a signing secret first (see securing webhooks).

Flask
import hmac, hashlib
from flask import Flask, request
app = Flask(__name__)
SECRET = "your_webhook_signing_secret"
@app.route("/webhook/delivery", methods=["POST"])
def delivery():
ts = request.headers.get("X-Webhook-Timestamp", "")
sig = request.headers.get("X-Webhook-Signature", "")
body = request.get_data(as_text=True)
if SECRET and sig:
expected = "sha256=" + hmac.new(
SECRET.encode(), f"{ts}.{body}".encode(), hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig, expected):
return "Bad signature", 401
data = request.get_json()
print(f"DLR: {data['message_id']} -> {data['status']}")
return "OK", 200
  • Endpoint is HTTPS and responds 2xx in well under 5 seconds.
  • Handler is idempotent — retries can deliver the same event twice.
  • Signature verification enabled (securing webhooks).
  • Alerting on webhook failures — check delivery logs periodically.