Making Voice Calls

Start outgoing calls, control them with TwiML instructions, and track final call results

Start an outgoing call, provide instructions for what happens when it connects, and receive the final call result.

Before you begin

You need your TextGrid Account SID and Auth Token, a sending number enabled for voice calls on your account, and a destination phone number.

Prepare two public endpoints:

  • An instructions endpoint that returns TwiML XML to control the call.
  • A status endpoint that records the final call result and acknowledges the notification.

The phone numbers, URLs, and identifiers below are fictitious. Replace them with your own values.

1. Prepare your call instructions

Your instructions endpoint should verify the incoming webhook signature, then return HTTP 200 with Content-Type: application/xml and a TwiML response.

For a simple spoken message, return:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Hello. This is a reminder about your upcoming appointment.</Say>
</Response>

When there are no more TwiML instructions to process, the call hangs up automatically.

The implemented verbs are Say, Dial, Gather, Play, Pause, Redirect, Hangup, and Ring. Support for a verb does not imply support for every Twilio attribute or nested element.

Hangup ends the entire conference if the call belongs to one. The example above is intended for a standalone call.

See Voice Webhooks for instruction fields, keypad collection, redirects, and verb behavior.

2. Create the outgoing call

Send a POST request with a JSON body:

POST https://api.textgrid.com/2010-04-01/Accounts/YOUR_ACCOUNT_SID/Calls.json
Content-Type: application/json
Authorization: Bearer YOUR_BASE64_ENCODED_CREDENTIALS

For authentication, Base64-encode the literal AccountSid:AuthToken pair. Keep these credentials on your server; see Getting Started with TextGrid.

Example request body:

{
  "From": "+12025550100",
  "To": "+12025550101",
  "Url": "https://example.com/voice/instructions",
  "Method": "POST",
  "StatusCallback": "https://example.com/voice/status",
  "StatusCallbackMethod": "POST"
}
FieldDescription
FromCalling phone number. Required; use an eligible voice number for your account.
ToDestination phone number. Required.
UrlYour endpoint that returns TwiML instructions.
MethodHTTP method used to request instructions. The example explicitly selects POST.
StatusCallbackYour endpoint for final call status notifications.
StatusCallbackMethodHTTP method for status notifications. Defaults to POST; GET is also supported.

Keep phone numbers as strings in E.164 format, including the leading +.

3. Save the call identifier

Check the HTTP status and response body. Save the returned sid with your application's call record so you can match later callbacks and retrieve the call.

Useful response fields include sid, status, from, to, direction, and duration. Fields with null values can be omitted.

A successful creation response does not mean the destination answered or heard the message. Use the final status notification to track the outcome.

4. Handle instruction requests

With Method set to POST, TextGrid sends application/x-www-form-urlencoded fields to your Url. With GET, the fields appear in the URL query string instead. These callbacks do not contain JSON bodies.

Instruction fields include CallSid, AccountSid, From, To, CallStatus, and Direction.

For outgoing initial instruction requests, the current API sends Direction=outbound and CallStatus=ringing. Subsequent Gather, Redirect, and machine-detection instruction requests send CallStatus=in-progress. Return the next TwiML instructions rather than relying on the initial status label to determine what to do.

Verify X-TextGrid-Signature using your account's Webhook Secret before processing the request. Capture the raw POST body before parsing form fields. See Verifying Webhook Signatures for the algorithm and code samples.

5. Receive the final call result

Your status endpoint receives a notification with CallStatus set to completed, busy, no-answer, or failed. Match its CallSid to the call identifier you saved.

Outgoing final-status notifications use Direction=outbound-api; instruction requests use outbound.

Verify the signature, record the result, and return HTTP 200. An empty body is sufficient. Status notifications do not request TwiML.

Where present, CallDuration reports seconds and Duration reports minutes rounded up. Failed-event notifications omit these duration fields. See Voice Webhooks for the complete field list and conditional values.

The final-status sender makes one request without an automatic retry loop. An upstream event can repeat, so make processing idempotent and do not rely on SequenceNumber for ordering or duplicate detection.

Answering-machine detection

Answering-machine detection depends heavily on the type of phone line and the destination carrier. Accuracy and the time needed to classify an answer can vary, so detection is not guaranteed to identify every human or answering machine correctly. Test with the line types and carriers your recipients use, and design your call flow to handle incorrect or delayed results.

If your application needs to distinguish a human answer from an answering machine, consult the API Reference for the MachineDetection options supported by your account and provider. Additional settings and behavior depend on that support.

When detection is enabled, the instruction request can include AnsweredBy with human, machine_start, machine_end_beep, or machine_end_other, plus an optional reason field. Return TwiML appropriate to the result.

With DetectMessageEnd, a machine result can be delayed until greeting-end detection. Do not assume every instruction request contains a detection result. See Voice Webhooks for the detection callback contract.

Retrieve a call

Retrieve a call using the saved SID:

GET https://api.textgrid.com/2010-04-01/Accounts/YOUR_ACCOUNT_SID/Calls/YOUR_CALL_SID.json
Authorization: Bearer YOUR_BASE64_ENCODED_CREDENTIALS

Use this record to check current information or reconcile a missing status callback. Some specialized account integrations handle call events separately, so a generic status callback is not guaranteed for every call leg.

Handle errors and retries

Check the HTTP status first. Error bodies vary and can be empty. Preserve the status and response body for troubleshooting while protecting credentials and customer information.

If a request is rejected, correct the reported issue before trying again. Check the account, calling number, destination, and callback configuration as applicable.

If a create-call request times out before you receive a response, the call may already have been created. Check available call records and callbacks before retrying. Repeating the POST request can place another call and incur additional charges.


Did this page help you?