Skip to contentSkip to navigationSkip to topbar
Page tools
Useful for sharing or LLM
Accelerate development with AI

On this page
Looking for more inspiration?Visit the

Webhooks configuration API


(information)

Legal Notice

Webhooks configuration API is not PCI compliant or a HIPAA Eligible Service and should not be used in workflows that are subject to HIPAA or PCI.

With the Webhooks configuration API, you control how Twilio authenticates, signs, and delivers each outbound webhook, based on the webhook's URL.

Use it to authenticate Twilio to your endpoints with OAuth 2.0, Basic, or Digest credentials, to sign requests with a key you manage instead of your account authentication token, and to set the timeouts, retries, and edge zones Twilio uses when delivering a webhook.


Base URL

base-url page anchor
https://webhooks.twilio.com/v1/Webhooks

Every request uses HTTP basic authentication. Use an API key SID as the username and the API key secret as the password.

1
curl -X GET https://webhooks.twilio.com/v1/Webhooks/Settings \
2
-u {API_KEY_SID}:{API_KEY_SECRET}

You can use your account SID and authentication token instead, but limit that to local testing.


Two resources do the main work, and the rest support them.

ResourceWhat it holds
SettingsOne complete delivery configuration: authentication, signing, connection, and edge zones.
RulesA URL match pattern, and the Settings to apply to webhooks matching it.
AuthProfilesReusable credentials that several Settings can share.
SharedKeysSigning keys used to sign webhook requests.
OperationsThe status of an in-flight Rule change.
TestsA single test delivery against a Setting.
EdgeZonesThe catalog of edge zones you can deliver from.

A Setting on its own changes nothing. Twilio applies a Setting only when a Rule points a matching webhook URL at it.


How Twilio applies a configuration

how-twilio-applies-a-configuration page anchor

When Twilio sends a webhook, it compares the destination URL against your Rules and applies the Setting that the winning Rule names. That Setting is the whole configuration for the request: Twilio uses its authentication, signing, connection, and edge zone values, and ignores anything the webhook URL carries. The exception is the system Setting, which reproduces legacy delivery and does read credentials and overrides from the URL.

If no Rule matches, Twilio delivers the webhook using the legacy URL-based behavior instead. HTTP authentication and connection overrides come from the URL, and Twilio signs with your account authentication token. A webhook you configured before adopting this API keeps that behavior until you create a Rule that covers it.


See which configuration applied

see-which-configuration-applied page anchor

A webhook this API configures carries an X-Twilio-Webhooks-Settings header naming what Twilio applied:

X-Twilio-Webhooks-Settings: rule=<ruleId>,setting=<settingId>

setting= names the Setting Twilio used. rule= names the Rule that matched, and appears only when one did. A test runs without a Rule, so its header carries setting= alone. A webhook that no Rule matches carries no header, because Twilio delivered it with legacy behavior.

When a shared key signed the webhook, X-Twilio-Webhooks-Signature-Settings names the key and algorithm. See Sign webhooks with shared keys.


This creates a configuration that signs the webhooks Twilio sends to one URL with a key you control. Rules apply to a single Twilio account, so run it in a test account before your production one.

(information)

Already receiving webhooks on this URL?

This quickstart assumes no live traffic reaches the URL yet. If webhooks already reach it, or you aren't sure, follow Migrate to the configuration API instead: it shifts traffic gradually and is reversible at every step.

  1. Create a SharedKey and save the returned secret. This is the only response that contains it.

    1
    curl -X POST https://webhooks.twilio.com/v1/Webhooks/SharedKeys \
    2
    -H 'Content-Type: application/json' \
    3
    -u {API_KEY_SID}:{API_KEY_SECRET} \
    4
    -d '{ "friendlyName": "Primary signing key" }'
  2. Update your endpoint to accept the new signature. Validate with the shared key secret when a request carries X-Twilio-Webhooks-Signature-Settings, and keep your account authentication token validation for requests without it. Supporting both means no downtime at cutover.

  3. Create a Setting that signs with that key. auth is required, so use NONE if you don't want Twilio to authenticate itself to your endpoint.

    1
    curl -X POST https://webhooks.twilio.com/v1/Webhooks/Settings \
    2
    -H 'Content-Type: application/json' \
    3
    -u {API_KEY_SID}:{API_KEY_SECRET} \
    4
    -d '{
    5
    "friendlyName": "Signed webhooks",
    6
    "auth": { "source": "INLINE", "value": { "scheme": "NONE" } },
    7
    "signature": {
    8
    "type": "SHARED_KEY",
    9
    "sharedKeyId": "{SHARED_KEY_ID}",
    10
    "algorithm": "HMAC_SHA256"
    11
    }
    12
    }'
  4. Test the Setting against your endpoint before any live traffic uses it.

    1
    curl -X POST https://webhooks.twilio.com/v1/Webhooks/Tests \
    2
    -H 'Content-Type: application/json' \
    3
    -u {API_KEY_SID}:{API_KEY_SECRET} \
    4
    -d '{
    5
    "url": "https://example.com/webhooks",
    6
    "settingId": "{SETTING_ID}",
    7
    "method": "POST"
    8
    }'
    (warning)

    Let the Setting propagate before testing

    A Setting needs 30 to 90 seconds to reach the Twilio webhook delivery plane, and a test sent before then returns a 422 error.

  5. Create a Rule so the Setting applies to that URL. This returns 202 Accepted.

    1
    curl -X POST https://webhooks.twilio.com/v1/Webhooks/Rules \
    2
    -H 'Content-Type: application/json' \
    3
    -u {API_KEY_SID}:{API_KEY_SECRET} \
    4
    -d '{
    5
    "matchType": "EXACT_MATCH",
    6
    "value": "https://example.com/webhooks",
    7
    "settings": [ { "settingId": "{SETTING_ID}", "percentage": 100 } ]
    8
    }'
  6. Poll the Operation-Id from the previous response until its status is COMPLETED.

    1
    curl -X GET https://webhooks.twilio.com/v1/Webhooks/Operations/{OPERATION_ID} \
    2
    -u {API_KEY_SID}:{API_KEY_SECRET}
  7. Confirm on live traffic. The next webhook Twilio sends to that URL carries an X-Twilio-Webhooks-Settings header naming your Rule and Setting, and your validation should accept its signature.

To undo this, delete the Rule. Its webhooks go to the next Rule that matches them, or to legacy delivery if no Rule does.


Settings, AuthProfiles, and SharedKeys accept changes only to friendlyName and, where present, description. To change any part of a configuration, create a new resource and point your Rule at it. Nothing you already deployed changes underneath you, and you roll forward or back by editing one Rule.

Rules are the exception: you can change a Rule's match pattern and its Settings in place.


Changes take 30 to 90 seconds to take effect

changes-take-30-to-90-seconds-to-take-effect page anchor

Every write is saved immediately, and you can reference a resource right after you create it. Reaching the plane that delivers your webhooks is a separate step that takes 30 to 90 seconds.

The window shows up in two places:

  • Sending a webhook: A Rule change returns 202 Accepted with an Operation-Id header. Poll that Operation to see when the change is live. Until then, webhooks may still use the previous configuration.
  • Testing a Setting: A test sent inside the window returns a 422 error. Retry after it passes.

AuthProfiles and SharedKeys take effect through the Setting that links them.


Each account can hold up to 50 of each resource type: SharedKeys, AuthProfiles, Settings, and Rules. Exceeding a limit returns error 59200. To request an increase, contact Twilio Support(link takes you to an external page).

Only one DEFAULT Rule is allowed per account.


List endpoints accept pageSize (default 50, maximum 1000) and pageToken. Each response carries a meta object with nextToken and previousToken when more pages exist.

1
curl -X GET 'https://webhooks.twilio.com/v1/Webhooks/Settings?pageSize=100' \
2
-u {API_KEY_SID}:{API_KEY_SECRET}