Phone Numbers
Connect a SIP-trunk number
Connect a phone number from any carrier over SIP trunking, and choose the assistants that answer it and dial from it.
POST
/
phone-number
/
sip
Connect a SIP-trunk number
curl --request POST \
--url https://api.verbeo.ai/v1/phone-number/sip \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phone_number": "<string>",
"termination_uri": "<string>",
"transport": "<string>",
"sip_username": "<string>",
"sip_password": "<string>",
"nickname": "<string>",
"inbound_agent_id": "<string>",
"outbound_agent_id": "<string>"
}
'import requests
url = "https://api.verbeo.ai/v1/phone-number/sip"
payload = {
"phone_number": "<string>",
"termination_uri": "<string>",
"transport": "<string>",
"sip_username": "<string>",
"sip_password": "<string>",
"nickname": "<string>",
"inbound_agent_id": "<string>",
"outbound_agent_id": "<string>"
}
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({
phone_number: '<string>',
termination_uri: '<string>',
transport: '<string>',
sip_username: '<string>',
sip_password: '<string>',
nickname: '<string>',
inbound_agent_id: '<string>',
outbound_agent_id: '<string>'
})
};
fetch('https://api.verbeo.ai/v1/phone-number/sip', 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://api.verbeo.ai/v1/phone-number/sip",
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([
'phone_number' => '<string>',
'termination_uri' => '<string>',
'transport' => '<string>',
'sip_username' => '<string>',
'sip_password' => '<string>',
'nickname' => '<string>',
'inbound_agent_id' => '<string>',
'outbound_agent_id' => '<string>'
]),
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 := "https://api.verbeo.ai/v1/phone-number/sip"
payload := strings.NewReader("{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\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("https://api.verbeo.ai/v1/phone-number/sip")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.verbeo.ai/v1/phone-number/sip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyConnects a number you own at a carrier to Verbeo over SIP trunking: Verbeo sets up the trunks that carry the number’s inbound and outbound calls, then stores the number. It works with any carrier that gives you a SIP trunk — for Twilio Elastic SIP Trunking, Import a phone number from Twilio covers the carrier side.
Nothing is left behind when a request fails — a trunk that was created is removed again, so the same request can be sent once more.
Inbound calls arrive once your carrier sends the number’s calls to Verbeo’s origination URI,
sip:1mq55afrqof.sip.livekit.cloud. That is set at the carrier, not through this API.Body
string
required
The number in E.164 format — a
+, the country code, the number: +14155550123. Spaces, dashes and brackets are accepted and removed. A number without its country code, or one that is not a real number, is rejected.string
required
The host your carrier takes outbound calls on, optionally with a port:
acme.pstn.twilio.com or sip.example.com:5061. No sip: or https:// in front. Up to 253 characters.string
default:"tcp"
tcp, udp, tls or auto.string
The trunk’s user name, if your carrier authenticates outbound calls with credentials. Up to 128 characters. Send it together with
sip_password, or send neither.string
The trunk’s password, stored as you send it. Up to 128 characters. Write-only: no endpoint returns it.
string
Your label for the number, up to 100 characters.
string
UUID of the assistant that answers calls to this number. Omit it and nobody answers until you set one.
string
UUID of the assistant that places calls from this number when a call names none.
Request
curl -X POST "https://api.verbeo.ai/v1/phone-number/sip" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+14155550123",
"termination_uri": "acme.pstn.twilio.com",
"sip_username": "verbeo",
"sip_password": "a-strong-password",
"nickname": "Main line",
"inbound_agent_id": "550e8400-e29b-41d4-a716-446655440000"
}'
const res = await fetch("https://api.verbeo.ai/v1/phone-number/sip", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VERBEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
phone_number: "+14155550123",
termination_uri: "acme.pstn.twilio.com",
sip_username: "verbeo",
sip_password: process.env.SIP_TRUNK_PASSWORD,
nickname: "Main line",
inbound_agent_id: "550e8400-e29b-41d4-a716-446655440000",
}),
});
const { data: number } = await res.json();
import os, requests
res = requests.post(
"https://api.verbeo.ai/v1/phone-number/sip",
headers={"Authorization": f"Bearer {os.environ['VERBEO_API_KEY']}"},
json={
"phone_number": "+14155550123",
"termination_uri": "acme.pstn.twilio.com",
"sip_username": "verbeo",
"sip_password": os.environ["SIP_TRUNK_PASSWORD"],
"nickname": "Main line",
"inbound_agent_id": "550e8400-e29b-41d4-a716-446655440000",
},
)
number = res.json()["data"]
Response
201 Created with the phone number object. provider is livekit_sip.
{
"success": true,
"data": {
"id": "7d9f3b52-4c1e-4a8e-9b1a-2f6c0d4e8a11",
"workspace_id": "123e4567-e89b-12d3-a456-426614174000",
"phone_number": "+14155550123",
"nickname": "Main line",
"provider": "livekit_sip",
"is_active": true,
"max_cps": 1,
"inbound_agent_id": "550e8400-e29b-41d4-a716-446655440000",
"outbound_agent_id": null,
"inbound_webhook_url": null,
"created_at": "2026-01-15T10:30:00.123456+00:00",
"updated_at": "2026-01-15T10:30:00.123456+00:00",
"inbound_agent_name": "Customer Support",
"outbound_agent_name": null
}
}
Errors
| Code | Status | When |
|---|---|---|
VALIDATION_FAILED | 422 | A missing or malformed field — the message names it, e.g. termination_uri: must be a hostname such as example.pstn.twilio.com, optionally with :port. Also a user name without a password (or the reverse), and an assistant id that is not an assistant of your workspace. |
CONFLICT | 409 | The number is already connected to Verbeo, in your workspace or another. |
BAD_GATEWAY | 502 | The trunk could not be created. The message carries the reason. |
Was this page helpful?
⌘I
Connect a SIP-trunk number
curl --request POST \
--url https://api.verbeo.ai/v1/phone-number/sip \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phone_number": "<string>",
"termination_uri": "<string>",
"transport": "<string>",
"sip_username": "<string>",
"sip_password": "<string>",
"nickname": "<string>",
"inbound_agent_id": "<string>",
"outbound_agent_id": "<string>"
}
'import requests
url = "https://api.verbeo.ai/v1/phone-number/sip"
payload = {
"phone_number": "<string>",
"termination_uri": "<string>",
"transport": "<string>",
"sip_username": "<string>",
"sip_password": "<string>",
"nickname": "<string>",
"inbound_agent_id": "<string>",
"outbound_agent_id": "<string>"
}
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({
phone_number: '<string>',
termination_uri: '<string>',
transport: '<string>',
sip_username: '<string>',
sip_password: '<string>',
nickname: '<string>',
inbound_agent_id: '<string>',
outbound_agent_id: '<string>'
})
};
fetch('https://api.verbeo.ai/v1/phone-number/sip', 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://api.verbeo.ai/v1/phone-number/sip",
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([
'phone_number' => '<string>',
'termination_uri' => '<string>',
'transport' => '<string>',
'sip_username' => '<string>',
'sip_password' => '<string>',
'nickname' => '<string>',
'inbound_agent_id' => '<string>',
'outbound_agent_id' => '<string>'
]),
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 := "https://api.verbeo.ai/v1/phone-number/sip"
payload := strings.NewReader("{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\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("https://api.verbeo.ai/v1/phone-number/sip")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.verbeo.ai/v1/phone-number/sip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"phone_number\": \"<string>\",\n \"termination_uri\": \"<string>\",\n \"transport\": \"<string>\",\n \"sip_username\": \"<string>\",\n \"sip_password\": \"<string>\",\n \"nickname\": \"<string>\",\n \"inbound_agent_id\": \"<string>\",\n \"outbound_agent_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body