Create an app voice call
curl --request POST \
--url http://localhost:8080/phone/web-calls \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"contactId": "<string>",
"destination": {
"type": "agent",
"id": "<string>"
},
"maxDurationSeconds": 1800
}
'import requests
url = "http://localhost:8080/phone/web-calls"
payload = {
"requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"contactId": "<string>",
"destination": {
"type": "agent",
"id": "<string>"
},
"maxDurationSeconds": 1800
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
requestId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
contactId: '<string>',
destination: {type: 'agent', id: '<string>'},
maxDurationSeconds: 1800
})
};
fetch('http://localhost:8080/phone/web-calls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/phone/web-calls",
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([
'requestId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'contactId' => '<string>',
'destination' => [
'type' => 'agent',
'id' => '<string>'
],
'maxDurationSeconds' => 1800
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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 := "http://localhost:8080/phone/web-calls"
payload := strings.NewReader("{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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("http://localhost:8080/phone/web-calls")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/phone/web-calls")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}"
response = http.request(request)
puts response.read_body{
"callId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sessionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"controlToken": "<string>",
"expiresAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}AI Phone Agents
Create an app voice call
Create app voice call through the Voice SDK integration. Use with the authentication and customer identity flow described in the app voice guide.
POST
/
phone
/
web-calls
Create an app voice call
curl --request POST \
--url http://localhost:8080/phone/web-calls \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"contactId": "<string>",
"destination": {
"type": "agent",
"id": "<string>"
},
"maxDurationSeconds": 1800
}
'import requests
url = "http://localhost:8080/phone/web-calls"
payload = {
"requestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"contactId": "<string>",
"destination": {
"type": "agent",
"id": "<string>"
},
"maxDurationSeconds": 1800
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
requestId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
contactId: '<string>',
destination: {type: 'agent', id: '<string>'},
maxDurationSeconds: 1800
})
};
fetch('http://localhost:8080/phone/web-calls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/phone/web-calls",
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([
'requestId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'contactId' => '<string>',
'destination' => [
'type' => 'agent',
'id' => '<string>'
],
'maxDurationSeconds' => 1800
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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 := "http://localhost:8080/phone/web-calls"
payload := strings.NewReader("{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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("http://localhost:8080/phone/web-calls")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/phone/web-calls")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requestId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"contactId\": \"<string>\",\n \"destination\": {\n \"type\": \"agent\",\n \"id\": \"<string>\"\n },\n \"maxDurationSeconds\": 1800\n}"
response = http.request(request)
puts response.read_body{
"callId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sessionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"controlToken": "<string>",
"expiresAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}See Voice SDK integration for authentication, platform packages, routing, and preview availability.
Enable Allow calls from apps in Settings → Voice & Telephony for this organization. Disabling it blocks new calls and activation of pending calls; active calls can finish.
Call this endpoint from your authenticated server with a
phone:write API key. Resolve contactId from the signed-in customer and choose an authorized destination: either { type: 'agent', id } or { type: 'team', id }.
Reuse the UUID requestId for identical retries until activation. Changed settings or retries after activation return 409. maxDurationSeconds defaults to 1800 and accepts integers from 60 to 3600; the duration starts at activation.
A successful response is HTTP 200 with callId, sessionId, controlToken, and expiresAt. Pass this object unchanged to the OpenCX SDK; it manages the audio connection internally. Audio connection URLs and participant credentials are not part of this response. Join and activate within two minutes. expiresAt is the outer call-control deadline, not an extension of that join window. Credentials must be returned only to the authenticated customer and must not be logged or cached.
Creation returns 400 for invalid settings or unsupported agent transfers, 401 for invalid authentication, 403 for missing scope, disabled app calling, or a blocked contact, 404 for an unavailable contact/destination, 409 for conflicting or active calls, and 429 when requests are throttled.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
Reuse for retries of the same call creation request.
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Verified contact belonging to your organization. Resolve this on your server.
Required string length:
1 - 100- Option 1
- Option 2
Show child attributes
Show child attributes
Required range:
60 <= x <= 3600Response
Default Response
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Pattern:
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$Was this page helpful?