Webhooks
One application can provide another application with real-time updates via a webhook (also referred to as a web callback or HTTP push API). A webhook delivers data to other applications as it happens, meaning you get data immediately. In the past, APIs would typically need to poll for data very frequently to get it promptly. This makes webhooks much more efficient for both provider and consumer. The only drawback to webhooks is the difficulty of initially setting them up - this tutorial walks through how to consume webhooks.
Webhooks are sometimes referred to as “Reverse APIs,” as they give you what amounts to an API spec, and you must design an API for the webhook to use. The webhook will make an HTTP request to your app (typically a POST), and you will then be charged with interpreting it.
Telnyx can send webhook events that notify your application any time an event happens on your account. This is especially useful for events like receiving an SMS or MMS message and getting feedback on Call Control events. The messaging webhooks section goes into a bit more detail on how SMS and MMS webhooks work.
HTTP and HTTPS
- Unsecure (HTTP) URLs are allowed for webhooks.
- If HTTPS (TLS) is used, the certificate will be validated.
Event Type Naming
Where possible, events map to the C(R)UD operations, but this is certainly not always be applicable.
- resource.created
- resource.updated
- resource.deleted
When the CRUD operations are not applicable, events will be named with past tense verbs.
- message.created
- message.deleted
- message.delivered
- message.received
- porting sub request.ported
- porting sub request.closed
Structure
The top-level structure of the webhook will vary by product but not by type of event received. For example, Call Control webhooks have a different top-level structure than Messaging webhooks however the webhook structure across all Call Control commands is consistent. The payload
of the webhook contains the most valuable information for your application.
Call Control Top-Level Structure
{
"call_leg_id": "e97d8d4c-1a25-11cd-bc67-02620a0f6d42",
"call_session_id": "e97da4f0-1a25-11bd-909f-02620a0f6d642",
"event_timestamp": "2019-11-10T22:25:27.521992Z",
"metadata": {
"attempt": 1,
"delivered_to": "https://www.example.com/callback",
"event": {
"event_type": "call.initiated",
"id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0",
"occurred_at": "2019-11-10T22:25:27.521992Z",
"payload": {
...
},
"record_type": "event"
},
"status": "delivered"
},
"name": "call.initiated",
"organization_id": null,
"type": "webhook",
"user_id": "901dbc74-1597-4d15-aad2-xxxxxxxxxxxx"
}
Note: After pasting the above content, Kindly check and remove any new line added
FIELD NAME | DESCRIPTION |
call_leg_id |
ID that is unique to the call and can be used to correlate webhook events. |
call_session_id |
ID that is unique to the call session and can be used to correlate webhook events. |
event_timestamp |
ISO 8601 datetime of when the event occurred. |
attempt |
The number of attempts made to deliver the webhook. Multiple attempts will occur if your application does not send Telnyx HTTP 200 OK on receipt of the webhook. |
delivered_to |
URL that the webhook was sent to. |
event_type |
The type of event being delivered which also determines the structure of the payload . |
id |
Unique ID of the event. |
occurred_at |
ISO 8601 datetime of when the event occurred. |
record_type |
Will always be event . |
status |
Status of the webhook for debugging purposes. |
name |
Event name. |
organization_id |
ID of the organization. |
Messaging Top-Level Structure
{
"data": {
"event_type": "message.finalized",
"id": "4ef8c3a6-4195-4389-b3a6-38e3cb9eb4ae",
"occurred_at": "2019-11-10T22:30:14.148+00:00",
"payload": {
...
},
"record_type": "event"
},
"meta": {
"attempt": 1,
"delivered_to": "https://www.example.com/messaging"
}
}
Note: After pasting the above content, Kindly check and remove any new line added
FIELD NAME | DESCRIPTION |
event_type |
The type of event being delivered which also determines the structure of the payload . |
id |
Unique ID of the event. |
occurred_at |
ISO 8601 datetime of when the event occurred. |
payload |
The main data for the event. The structure is denoted by the event_type . |
record_type |
Will always be event . |
attempt |
The number of attempts made to deliver the webhook. Multiple attempts will occur if your application does not send Telnyx a 2xx HTTP status code within 2s of receipt of the webhook. |
delivered_to |
URL that the webhook was sent to. |
Full Call Control Example
{
"call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1",
"event_timestamp": "2019-11-10T22:26:27.521992Z",
"metadata": {
"attempt": 1,
"delivered_to": "https://www.example.com/callback",
"event": {
"event_type": "call.answered",
"id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0",
"occurred_at": "2019-11-10T22:26:27.521992Z",
"payload": {
"call_control_id": "v2:F5_vIJVqrosogeY_2L_JhCEHd2Dh-x4xz7tROTbh34tg6Zsk4JJc-w",
"call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1",
"client_state": null,
"connection_id": "7267xxxxxxxxxxxxxx",
"from": "+8005550199",
"start_time": "2019-11-10T22:26:26.521992Z",
"to": "+8005550100",
},
"record_type": "event"
},
"status": "delivered"
},
"name": "call.answered",
"organization_id": null,
"type": "webhook",
"user_id": "901dbc74-1597-4d15-aad2-xxxxxxxxxxxx"
}
Note: After pasting the above content, Kindly check and remove any new line added
Responding to a webhook
To acknowledge receipt of a webhook, your endpoint should return a 2xx
HTTP status code. Any other information returned in the request headers or request body is ignored. All response codes outside this range, including 3xx
codes, will indicate to Telnyx that you did not receive the webhook. URL redirection or a "Not Modified" response will be treated as a failure.
Retries
Webhooks will be retried to each of the supplied URLs if your application does not respond in 2000 milliseconds.
Best Practices
If your webhook script performs complex logic or makes network calls, it's possible the script would timeout before Telnyx sees its complete execution. For that reason, you may want to have your webhook endpoint immediately acknowledge receipt by returning a 2xx
HTTP status code, and then perform the rest of its duties.
Webhook endpoints may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you've processed, and then not processing already-logged events. Additionally, we recommend verifying webhook signatures to confirm that received events are being sent from Telnyx.
Webhook Signing
Telnyx signs the webhook events it sends to clients so that the authenticity of the request can be verified. Webhook signing in API V2 uses public key encryption. Telnyx stores a public-private key pair and uses the private key to sign the payload. The public key is available to you so that you can verify the request.
The public key can be viewed in the Mission Control Portal.
The signature for the payload is calculated by building a string that is the combination of the timestamp of when the request was initiated, the pipe |
character and the JSON payload. The signature is then Base64
encoded.
Base64.encode64("#{timestamp}|#{payload}")
The signature (Base64
encoded) and the timestamp (in Unix format) are assigned to the request headers telnyx-signature-ed25519
and telnyx-timestamp
respectively.
You can then use cryptographic libraries in your language of choice to verify the signature using the public key. For examples, please see: