Prerequisites
- A Telnyx account with a phone number assigned to a messaging profile
- A publicly accessible HTTPS endpoint (or ngrok for local development)
- Your API key and public key (for signature verification)
How webhook delivery works
An event occurs
A message is received by your number, or a sent message changes status (queued → sent → delivered).
Telnyx sends a POST request
An HTTP
POST with a JSON payload is sent to your configured webhook URL.Webhook URL hierarchy
Telnyx determines where to send webhooks using this priority order:- Per-message URLs —
webhook_urlandwebhook_failover_urlin the send message request body - Messaging profile URLs — Configured on the messaging profile
- No webhook — If neither is set, no webhook is delivered (events are still available in Message Detail Records)
Webhook event types
Telnyx messaging produces the following webhook events:| Event Type | Trigger | Direction |
|---|---|---|
message.received | An inbound SMS/MMS arrives at your number | Inbound |
message.sent | An outbound message has been accepted and sent to the carrier | Outbound |
message.finalized | An outbound message has reached a terminal state (delivered, failed, etc.) | Outbound |
Payload structure
All messaging webhooks share this top-level structure:| Field | Description |
|---|---|
data.event_type | The event type (message.received, message.sent, message.finalized) |
data.id | Unique identifier for this webhook event |
data.occurred_at | ISO 8601 timestamp of when the event occurred |
data.payload | Message details (see examples below) |
data.record_type | Always "event" |
meta.attempt | Delivery attempt number (starts at 1) |
meta.delivered_to | The URL this webhook was delivered to |
Event examples
Inbound message (message.received)
Triggered when your Telnyx number receives an SMS or MMS:
MMS inbound payload (with media)
MMS inbound payload (with media)
MMS messages include a
media array with URLs, content types, and file sizes:Message sent (message.sent)
Triggered when an outbound message has been accepted by the downstream carrier:
Delivery receipt (message.finalized)
Triggered when a message reaches a terminal delivery state:
Delivery statuses
Theto[].status field in message.finalized events indicates the final delivery outcome:
| Status | Description |
|---|---|
queued | Message is queued on Telnyx’s side |
sending | Message is being sent to an upstream carrier |
sent | Message has been sent to the upstream carrier |
delivered | Carrier has confirmed delivery to the recipient |
sending_failed | Telnyx failed to send the message to the carrier |
delivery_failed | The carrier failed to deliver the message to the recipient |
delivery_unconfirmed | No delivery confirmation was received from the carrier |
Common delivery failure error codes
Common delivery failure error codes
When a message fails, the Common error codes:
For a complete list, see the Error Codes reference.
errors array in the payload contains details:| Code | Meaning |
|---|---|
40001 | Destination number invalid |
40002 | Destination number not in service |
40300 | Destination unreachable |
40008 | Message filtered by carrier |
40010 | Message blocked (spam/content filter) |
47000 | 10DLC campaign required |
Webhook signature verification
Telnyx signs every webhook using Ed25519 public key cryptography so you can verify that requests genuinely come from Telnyx. This is strongly recommended for production deployments. Each webhook request includes two headers:| Header | Description |
|---|---|
telnyx-signature-ed25519 | Base64-encoded Ed25519 signature |
telnyx-timestamp | Unix timestamp of when the request was signed |
{timestamp}|{json_payload}.
Get your public key
Find your public key in the Mission Control Portal under Keys & Credentials → Public Key.Verification examples
Timestamp tolerance: To prevent replay attacks, reject webhooks where
telnyx-timestamp is more than 5 minutes old.Handling webhooks in your application
Basic webhook handler
Retry behavior and error handling
Retry policy
| Behavior | Detail |
|---|---|
| Timeout | Your endpoint must respond within 2 seconds (API v2) |
| Retries | Up to 3 attempts per URL with exponential backoff |
| Failover | If all retries fail, Telnyx tries the failover URL (if configured) |
| Total attempts | Up to 6 total (3 primary + 3 failover) |
| Success response | Any 2xx status code |
| Failure response | Any non-2xx response, including 3xx redirects |
Best practices for reliability
- Respond immediately — Return
200before processing the event. Offload heavy logic to a background queue. - Handle duplicates — Webhooks may be delivered more than once. Use the
data.idfield as an idempotency key. - Handle out-of-order delivery — Events may arrive in a different order than they occurred. Use
data.occurred_attimestamps to sequence events. - Use HTTPS — Always use TLS-encrypted endpoints in production.
- Verify signatures — Validate
telnyx-signature-ed25519headers to prevent spoofing.
Webhook IP allowlist
If your server uses a firewall or ACL, allowlist the following Telnyx subnet:Troubleshooting
Webhooks not arriving
Webhooks not arriving
- Check your messaging profile — Confirm a webhook URL is configured in the Portal or via the API.
- Test your endpoint — Send a test POST request with
curlto ensure your server is accessible: - Check ngrok — If using ngrok, verify the tunnel is running and the URL matches your profile configuration.
- Check firewall — Ensure
192.76.120.192/27is allowlisted. - Check Message Detail Records — Events are logged regardless of webhook delivery. Check MDRs in the portal.
Getting duplicate webhooks
Getting duplicate webhooks
This is expected behavior. Telnyx may deliver the same webhook more than once, especially during retries. Track processed event IDs (For production, use a persistent store (Redis, database) instead of in-memory sets.
data.id) and skip duplicates:Webhooks arriving out of order
Webhooks arriving out of order
Telnyx does not guarantee delivery order. For example,
message.finalized may arrive before message.sent. Use the data.occurred_at timestamp to determine event sequence, and design your logic to handle any arrival order.Signature verification failing
Signature verification failing
- Ensure you’re reading the raw body — Parse the signature against the raw request body, not a re-serialized JSON object.
- Check your public key — Verify you’re using the correct public key from the Portal.
- Check timestamp tolerance — If you’re rejecting stale timestamps, ensure your server clock is synchronized (NTP).
Webhook timeouts (retries happening unexpectedly)
Webhook timeouts (retries happening unexpectedly)
Your endpoint must respond within 2 seconds. If your processing takes longer:
- Return
200immediately - Process the event asynchronously (use a message queue like Redis, RabbitMQ, or SQS)