Handle Twilio inbound PSTN call
curl --request POST \
--url https://your-instance.example.com/api/webhook/calls/twilio/inbound \
--header 'Content-Type: application/json' \
--data '
{
"To": "+12362320246",
"From": "+14165550100",
"CallSid": "CA5f7b1c2e8a1d4e0012c3b4a5",
"CallStatus": "ringing"
}
'import requests
url = "https://your-instance.example.com/api/webhook/calls/twilio/inbound"
payload = {
"To": "+12362320246",
"From": "+14165550100",
"CallSid": "CA5f7b1c2e8a1d4e0012c3b4a5",
"CallStatus": "ringing"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
To: '+12362320246',
From: '+14165550100',
CallSid: 'CA5f7b1c2e8a1d4e0012c3b4a5',
CallStatus: 'ringing'
})
};
fetch('https://your-instance.example.com/api/webhook/calls/twilio/inbound', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://your-instance.example.com/api/webhook/calls/twilio/inbound",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'To' => '+12362320246',
'From' => '+14165550100',
'CallSid' => 'CA5f7b1c2e8a1d4e0012c3b4a5',
'CallStatus' => 'ringing'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.example.com/api/webhook/calls/twilio/inbound"
payload := strings.NewReader("{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://your-instance.example.com/api/webhook/calls/twilio/inbound")
.header("Content-Type", "application/json")
.body("{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://your-instance.example.com/api/webhook/calls/twilio/inbound")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}"
response = http.request(request)
puts response.read_body"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Dial answerOnBridge=\"true\" record=\"record-from-answer\" recordingStatusCallback=\"/api/webhook/calls/twilio/recording\" recordingStatusCallbackMethod=\"POST\"><Client statusCallback=\"/api/webhook/calls/twilio/status\" statusCallbackMethod=\"POST\" statusCallbackEvent=\"initiated,ringing,answered,completed\">client_64a1b2c3d4e5f60012345679</Client></Dial></Response>"{
"error": "Webhook processing failed"
}Webhooks
Handle Twilio inbound PSTN call
Inbound PSTN webhook called by Twilio when a customer dials a Tether-provisioned Twilio number. Resolves the owning org/user, creates a Call record, and returns TwiML that dials the browser client (or the ElevenLabs voice agent when AI calling is enabled).
POST
/
api
/
webhook
/
calls
/
twilio
/
inbound
Handle Twilio inbound PSTN call
curl --request POST \
--url https://your-instance.example.com/api/webhook/calls/twilio/inbound \
--header 'Content-Type: application/json' \
--data '
{
"To": "+12362320246",
"From": "+14165550100",
"CallSid": "CA5f7b1c2e8a1d4e0012c3b4a5",
"CallStatus": "ringing"
}
'import requests
url = "https://your-instance.example.com/api/webhook/calls/twilio/inbound"
payload = {
"To": "+12362320246",
"From": "+14165550100",
"CallSid": "CA5f7b1c2e8a1d4e0012c3b4a5",
"CallStatus": "ringing"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
To: '+12362320246',
From: '+14165550100',
CallSid: 'CA5f7b1c2e8a1d4e0012c3b4a5',
CallStatus: 'ringing'
})
};
fetch('https://your-instance.example.com/api/webhook/calls/twilio/inbound', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://your-instance.example.com/api/webhook/calls/twilio/inbound",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'To' => '+12362320246',
'From' => '+14165550100',
'CallSid' => 'CA5f7b1c2e8a1d4e0012c3b4a5',
'CallStatus' => 'ringing'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.example.com/api/webhook/calls/twilio/inbound"
payload := strings.NewReader("{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://your-instance.example.com/api/webhook/calls/twilio/inbound")
.header("Content-Type", "application/json")
.body("{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://your-instance.example.com/api/webhook/calls/twilio/inbound")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"To\": \"+12362320246\",\n \"From\": \"+14165550100\",\n \"CallSid\": \"CA5f7b1c2e8a1d4e0012c3b4a5\",\n \"CallStatus\": \"ringing\"\n}"
response = http.request(request)
puts response.read_body"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Dial answerOnBridge=\"true\" record=\"record-from-answer\" recordingStatusCallback=\"/api/webhook/calls/twilio/recording\" recordingStatusCallbackMethod=\"POST\"><Client statusCallback=\"/api/webhook/calls/twilio/status\" statusCallbackMethod=\"POST\" statusCallbackEvent=\"initiated,ringing,answered,completed\">client_64a1b2c3d4e5f60012345679</Client></Dial></Response>"{
"error": "Webhook processing failed"
}Body
application/json
Tether-provisioned Twilio number that was dialed; used to resolve the owning org/user.
Caller phone number in E.164.
Twilio-assigned call identifier (CA…) for the inbound leg.
Twilio call state at webhook time, typically ringing for the inbound trigger.
Response
TwiML response. Dials the agent's browser client (or, when AI calling is enabled, the configured ElevenLabs agent number).
The response is of type string.
⌘I