Voice Webhooks

Receive call events, respond with voice instructions, collect keypad input, and track final call status.

Voice webhooks connect your application to the lifecycle of a call. TextGrid requests instructions from your server and sends a separate notification when the call ends.

Configure your callback URLs

Use separate endpoints for call instructions and final status notifications:

Call typeInstructions URLFinal status URL
IncomingThe phone number's voiceUrlThe phone number's statusCallback
OutgoingThe Url supplied when creating the callThe StatusCallback supplied when creating the call

For incoming instructions, configure the number's voiceMethod. For outgoing instructions, use the call's Method setting. Match your endpoint to the configured HTTP method.

Final status callbacks default to POST and also support GET.

MethodWhere callback fields appear
GETURL query parameters; no request body
POSTForm fields with Content-Type: application/x-www-form-urlencoded

These requests do not contain JSON bodies. Field names are case-sensitive.

Verify incoming requests

Verify the X-TextGrid-Signature header using your account's Webhook Secret before processing the request. TextGrid sends User-Agent: textgrid-api; the User-Agent alone does not authenticate a request.

See Verifying Webhook Signatures for the signing rules and C#, Node.js, and Python samples.

Capture the raw POST body before parsing form fields. For GET, preserve the exact public URL and encoded query string for verification.

Respond with call instructions

When TextGrid requests call instructions, return HTTP 200 with TwiML XML and Content-Type: application/xml.

For example, your instructions endpoint can return:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Thank you for calling.</Say>
</Response>

The current call-control handler implements these verbs:

VerbPurpose
SaySpeak text using text-to-speech.
DialDial a phone number and connect it to the existing call.
GatherCollect DTMF keypad input, optionally with a Say or Play prompt.
PlayPlay audio from a URL.
PauseWait before continuing to the next instruction.
RedirectRequest further instructions from another URL.
HangupEnd the call. If it belongs to a conference, end the entire conference.
RingPlay TextGrid's ringback audio while keeping the call open. This is a TextGrid extension used by specialized call flows.

Support for a verb does not imply support for every Twilio attribute or nested element.

Instruction request fields

The initial instruction request includes these fields. All are strings.

FieldDescription
CallSidIdentifier of the call.
AccountSidIdentifier of your TextGrid account.
FromCalling phone number.
ToCalled phone number.
CallStatusringing on the initial request; in-progress on subsequent Gather, Redirect, and machine-detection instruction requests.
ApiVersion2010-04-01.
Directioninbound or outbound.

Collect keypad input

Use Gather to collect DTMF input and request the next instructions from your application:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather action="https://example.com/voice/digits" numDigits="4" timeout="5">
    <Say>Please enter your four digit access code.</Say>
  </Gather>
  <Say>No input was received.</Say>
</Response>

Replace the example URL with your own endpoint. The Gather action URL and method, when supplied, take precedence over the call's instruction URL and method. Without an action URL, TextGrid uses the call's instruction URL.

The Gather request contains the instruction fields above plus Digits. Return the next TwiML response from your action endpoint.

Treat Digits as a string, preserving leading zeros and keypad characters. For example, 0012 must remain 0012.

Redirect to another instructions endpoint

Use Redirect to request further instructions from another URL:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Redirect>https://example.com/voice/next</Redirect>
</Response>

Redirect requests default to POST. Your target endpoint receives the instruction fields with CallStatus=in-progress and must return TwiML XML.

Handle answering-machine detection

When answering-machine detection is enabled for an outgoing call, the instruction request also includes:

FieldTypeDescription
AnsweredBystringhuman, machine_start, machine_end_beep, or machine_end_other.
reasonstringOptional additional reason. The field name is lowercase.

These requests use CallStatus=in-progress and Direction=outbound. Return TwiML for the next action.

With DetectMessageEnd, a machine result can be delayed until greeting-end detection. Your application should handle the documented values rather than assuming every request immediately identifies a human or machine.

Receive final call status

Final status notifications report one of these CallStatus values:

ValueMeaning
completedThe call completed.
busyThe destination was busy.
no-answerThe call was not answered.
failedThe call failed.

Your status endpoint should record the result and return HTTP 200. An empty response body is sufficient. Status notifications do not request TwiML instructions.

Status notification fields

All fields arrive as query or form text. Parse numeric values only after signature verification.

FieldParsed typeDescription
CallSidstringIdentifier of the call.
AccountSidstringIdentifier of your account.
FromstringCalling phone number.
TostringCalled phone number.
CalledstringCalled phone number.
Directionstringinbound or outbound-api. Note that outgoing instruction requests use outbound instead.
CallStatusstringcompleted, busy, no-answer, or failed.
ApiVersionstring2010-04-01.
TimestampstringUTC timestamp in ddd, dd MMM yyyy HH:mm:ss +0000 format.
CallbackSourcestringcall-progress-events.
SequenceNumberintegerCurrently 0; do not use it to determine event order.
SipResponseCodeintegerTextGrid's exposed result code; see below.
DigitsstringOptional captured keypad input. Preserve it as a string.
CallerstringIncluded in completion-event notifications; omitted in failed-event notifications.
DurationintegerDuration in minutes, rounded up. Included in completion-event notifications; omitted in failed-event notifications.
CallDurationintegerDuration in seconds. Included in completion-event notifications; omitted in failed-event notifications.

Missing or negative duration is reported as zero. The presence of duration fields depends on the event that generated the notification, not solely on the CallStatus value. Allow those fields to be absent.

SipResponseCode is 200 for a completed, positive-duration completion event, 400 for other completion events, and 404 for failed events. These values are not a complete provider SIP diagnostic record.

Handle delivery safely

The final-status sender makes one request and treats HTTP 200 as an acknowledgment. It does not provide an automatic retry loop or an exactly-once delivery guarantee.

An upstream event can repeat, so make status processing idempotent: receiving the same result again should not repeat billing, notifications, or other side effects. Do not rely on SequenceNumber for duplicate detection or ordering.

Some account integrations and specialized call flows handle events separately, so a generic final-status callback is not guaranteed for every call leg.

Troubleshoot callbacks

  • Confirm the callback URL and HTTP method match your endpoint.
  • Parse POST callbacks as form data and GET callbacks as query parameters.
  • Return XML from instruction endpoints and HTTP 200 from status endpoints.
  • If signature verification fails, check the exact public URL, query encoding, and unchanged raw POST body.
  • Keep identifiers and Digits as strings.
  • Allow optional fields to be absent and tolerate duplicate notifications.

Did this page help you?