Twilio

Twilio Webhook Not Working

A Twilio webhook fails when the endpoint is unreachable, returns non-2xx, or exceeds 15 seconds. Check the Console Debugger to read the error code.

Updated Jul 1, 2026

The short answer

"Twilio webhook not working" means Twilio sent an HTTP request to your configured URL but never got a usable reply, so your app's incoming SMS/voice handler, status callback, or event webhook silently fails. The fix: open the Twilio Console Debugger to read the exact error code (usually 11200), confirm your endpoint is publicly reachable and returns a 2xx within 15 seconds, and validate it accepts Twilio's POST requests.

When a Twilio webhook "isn't working," it almost always means one of three things: Twilio can't reach your URL, your endpoint replied with something other than a 2xx status (or didn't reply in time), or your code is rejecting the request because of signature or content-type handling. The single most useful first move is to read the actual error code in the Twilio Console Debugger rather than guessing.

What causes a Twilio webhook to fail?

A Twilio webhook is an HTTP request Twilio makes to your server when an event happens (an inbound SMS, an incoming call, a message status change, or a Debugger alert). It is not Twilio calling Twilio — your application is the server, and Twilio is the client. Per Twilio's Error 11200 ("HTTP retrieval failure") documentation, the request fails when Twilio "was unable to retrieve a successful response from your webhook URL." Concrete causes Twilio lists:

  • Your server returned a 4xx or 5xx status code instead of a 2xx.
  • The endpoint was unreachable — DNS didn't resolve, the connection was refused, or a firewall/WAF/rate limiter blocked Twilio's IPs.
  • The URL resolves to a private or localhost IP (a very common cause during local development — Twilio cannot reach localhost:3000).
  • The server rejected the HTTP method. Twilio sends most webhooks as POST with Content-Type: application/x-www-form-urlencoded; an endpoint that only handles GET, or that 404s on POST, will fail.
  • A redirect (3xx) pointed to an invalid or unreachable destination.
  • HTTP Basic Auth got in the way — Twilio recommends signature validation over HTTP auth.
  • The response timed out. Twilio waits a limited window before giving up — about 15 seconds (a hard, non-overridable ceiling for voice, due to the real-time nature of calls; the default read-timeout for other webhook types, which can vary by product — e.g., Conversations webhooks cap out at 5 seconds).
  • Content-Type mismatch on your response — for TwiML responses (SMS/voice), Twilio expects valid XML.

A separate failure mode that doesn't always raise 11200: your code receives the request but rejects it during signature validation, returning a 403. That still shows up as a non-2xx in the Debugger.

How do I fix a Twilio webhook that isn't working?

1. Read the error in the Console Debugger first. Go to Develop → Troubleshoot → Debugger (in the legacy Console, this is Monitor → Logs → Errors → Error logs) — the Twilio Debugger. Twilio logs the error code, severity, a more_info link, and — critically — a webhook subdocument containing the exact HTTP request Twilio sent and the response it got back (status code, headers, body). This tells you immediately whether the request even reached your server.

2. Test the URL the way Twilio does — a POST from the public internet. A browser GET is not a faithful test, because Twilio uses POST with form encoding. Reproduce it with curl:

curl -X POST 'https://yourdomain.com/your/webhook/path' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'From=+15551234567' \
--data-urlencode 'Body=test' -i

You want an HTTP 200 (or 204) back. For SMS/voice handlers, return valid TwiML with an XML content type, e.g.:

<?xml version="1.0" encoding="UTF-8"?>
<Response><Message>Got it.</Message></Response>

If you don't need to reply with TwiML, returning an empty 200/204 is fine.

3. Make sure the URL is publicly reachable. If you're developing locally, localhost won't work — put your app behind a public tunnel such as ngrok and point the Twilio webhook at the tunnel URL. To isolate "is it the network or my app?", temporarily set the webhook to a Webhook.site URL or a request-inspector like Pipedream's RequestBin (requestbin.net); if those receive the request, the problem is in your application, not the network path.

4. Verify the configured URL and method. In Phone Numbers → Manage → Active Numbers, select the number and confirm the "A message comes in" / "A call comes in" webhook URL and HTTP method (POST vs GET) match what your route expects. A trailing-slash redirect or a stale path is a frequent culprit.

5. Respond fast; process slowly. If your handler does real work (DB writes, downstream API calls) before responding, you can blow past the ~15s limit. Acknowledge immediately with a 200/202 and do the heavy work asynchronously (queue, background job).

6. If you validate signatures, validate correctly. Twilio signs every inbound request with an X-Twilio-Signature header computed as an HMAC-SHA1 over the full request URL plus the POST parameters, keyed by your Auth Token. The two most common reasons validation fails (and you wrongly return 403) are: the URL your app reconstructs doesn't byte-for-byte match what Twilio called (mismatched scheme/host/port behind a proxy or load balancer that terminates TLS — rebuild using the original https:// URL and forwarded host), and using the wrong Auth Token (e.g., a subaccount vs. main account). Use Twilio's helper libraries' RequestValidator rather than hand-rolling the HMAC.

7. Set a fallback URL on separate infrastructure so a single host outage doesn't drop every message.

With Courier

If you're sending SMS or other channels through Courier and configuring Twilio under the hood, the same rules apply to any callback endpoints you expose — return a 2xx quickly, keep the URL public, and check the Twilio Debugger for the raw request/response when something silently fails.

Note: There is no single SMTP-style numeric "webhook not working" code. The real diagnostic signal is the Twilio error code in the Debugger — most often 11200 — which is why reading the log is step one rather than a guess.

FAQ

Common questions

A browser issues a GET request; Twilio sends most webhooks as a POST with Content-Type application/x-www-form-urlencoded. If your route only handles GET (or 404s/405s on POST), it works in the browser but fails for Twilio. Test with a POST using curl and confirm you return a 2xx.

One API, every provider

Stop debugging raw provider errors

Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.

Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.