SIP Trunks
Last updated October 13, 2026
SIP trunks to upstream carriers and PBXs (REGISTER or static peering)
List configured SIP trunks
Responses
| Field | Type | Description | |
|---|---|---|---|
trunks | array[object] | required |
Create a SIP trunk (REGISTER or static peering)
Creates a typed SIP trunk. For type: "sip_register", VoiceBlender begins REGISTERing to the supplied registrar URI with digest auth, refreshes before expiry, and routes inbound INVITEs that arrive on that peer's socket plus outbound INVITEs whose from matches the AOR through the trunk. Set sip_register.outbound_proxy to send both the REGISTER and those INVITEs via a next-hop proxy instead of straight at the registrar; the Request-URI and digest authentication still target registrar_uri. It defaults to SIP_OUTBOUND_PROXY and is resolved at creation time, so the trunk snapshot reports the hop actually in effect. For type: "ip_ip", VoiceBlender peers with a fixed upstream without registering: the trunk is active at once, outbound INVITEs placed through it (by trunk_id on POST /v1/legs, or by a from matching ip_ip.aor) are routed at ip_ip.peer_uri with the trunk's optional digest credentials, and inbound INVITEs whose source address falls in ip_ip.inbound_sources are tagged with the trunk. Set ip_ip.options_ping_interval_seconds to health-check the peer with OPTIONS and receive sip.trunk_up / sip.trunk_down events.
Request Body
| Field | Type | Description | |
|---|---|---|---|
type | enum | required | Trunk type discriminator. `sip_register` REGISTERs to an upstream registrar; `ip_ip` peers with a fixed upstream without registering. Values: sip_register, ip_ip |
app_id | string | optional | Application identifier carried through to every event emitted by this trunk. |
sip_register | object | optional | Required when type == "sip_register". Configures the outbound REGISTER (registrar URI, AOR, digest credentials, expiry). |
registrar_uri | string | required | Upstream registrar SIP URI (e.g. "sip:pbx.example.com:5060" or "sips:pbx.example.com:5061"). Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Note that "transport" is a URI parameter (";"), not a URI header ("?") — RFC 3261 section 19.1. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's REGISTER and for outbound INVITEs placed from its AOR, attached as a loose `Route` header (the Request-URI is left unchanged, and digest auth still targets `registrar_uri`). E.g. "sip:edge.example.com:5060;transport=tcp". Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `registrar_uri`. |
aor | string | required | Address-of-record this trunk REGISTERs (e.g. "sip:alice@pbx.example.com"). Becomes the From URI on outbound REGISTER, and the From / P-Asserted-Identity host on outbound INVITEs placed `from` this AOR. |
username | string | optional | Digest auth username. Defaults to the AOR user-part when empty. |
password | string | required | Digest auth password. Required. Never returned in any response. |
contact_user | string | optional | Override the user-part of the Contact header sent in REGISTER. Defaults to the AOR user-part. |
expires_seconds | integer | optional | Requested registration lifetime in seconds. Clamped to [SIP_OUTBOUND_REGISTRATION_MIN_EXPIRES_SECONDS, SIP_OUTBOUND_REGISTRATION_MAX_EXPIRES_SECONDS]. Default: SIP_OUTBOUND_REGISTRATION_DEFAULT_EXPIRES_SECONDS (3600). |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` registrar or outbound proxy whose certificate is self-signed, privately signed, or carries no SAN (`x509: certificate relies on legacy Common Name field`). Scoped to that peer's hostname — every other TLS peer is still verified in full, unlike the server-wide `SIP_TLS_INSECURE_SKIP_VERIFY`. Ignored (with a logged warning) when the next hop is not TLS, or when it is named by IP literal: such a dial sends no SNI and cannot be told apart from any other, so use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. Prefer `SIP_TLS_CA_FILE` when the peer's CA can simply be trusted. |
ip_ip | object | optional | Required when type == "ip_ip". Configures static peering with a fixed upstream (peer URI, optional digest credentials, inbound source addresses, OPTIONS health check). |
peer_uri | string | required | SIP URI of the peer (e.g. "sip:203.0.113.10:5060" or "sips:sbc.carrier.example:5061"). Outbound calls placed through this trunk are routed here: with a loose `Route` header when the call's Request-URI names another host, and with none when it already targets the peer. Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Any user part is ignored. When the host is an IP literal it is also matched against the source of inbound INVITEs. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's outbound INVITEs and OPTIONS pings. When set, the INVITE carries a single loose `Route` naming the proxy, so the peer is only reached if the call's Request-URI names it. Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `peer_uri`. A proxy is never treated as an inbound source — list its address in `inbound_sources` if the peer's calls arrive through it. |
aor | string | optional | Optional identity this trunk presents (e.g. "sip:acme@carrier.example"). An outbound call whose `from` matches it, as a full URI or by user-part, is placed through this trunk without naming `trunk_id`; its host becomes the From / P-Asserted-Identity realm when `from` names none. Also used to tell apart several trunks that share an inbound source, by the To header. |
username | string | optional | Digest auth username for outbound INVITEs the peer challenges. Requires `password`. Defaults to the `aor` user-part when a password is set. |
password | string | optional | Digest auth password for outbound INVITEs the peer challenges. Optional — omit for a peer that authenticates by source address. Never returned in any response. |
inbound_sources | array[string] | optional | IP addresses and CIDR ranges (IPv4 or IPv6) that inbound INVITEs from this peer arrive from, e.g. ["198.51.100.0/24", "203.0.113.7"]. An inbound call whose source address falls in one is tagged with this trunk's `trunk_id` and inherits its `app_id`; when several trunks match, the longest prefix wins. This is a matching rule, not an access list: calls from other addresses are still accepted. The `peer_uri` host is included automatically when it is an IP literal; hostnames are never resolved. At most 64 entries; a /0 range is rejected. |
options_ping_interval_seconds | integer | optional | Seconds between OPTIONS health checks sent to the peer; 0 (the default) disables them. With checks on, the trunk's status follows the peer — `active` when it answers, `failed` when it does not — and `sip.trunk_up` / `sip.trunk_down` are published on each change. Any reply counts as up, including 404 or 405, except 408 and 5xx other than 501; no reply within 5 seconds counts as down. With checks off the trunk stays `active`. Status is informational: calls are attempted on a `failed` trunk too. 0 |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` peer or outbound proxy whose certificate is self-signed or privately signed. Scoped to that peer's hostname — every other TLS peer is still verified in full. Ignored (with a logged warning) when the next hop is not TLS or is named by IP literal; use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. |
Responses
| Field | Type | Description | |
|---|---|---|---|
id | string | required | |
type | string | required | |
status | string | required |
| Field | Type | Description | |
|---|---|---|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Get a single SIP trunk
Parameters
| Name | In | Type | Description | |
|---|---|---|---|---|
id | path | string | required | Leg ID |
Responses
| Field | Type | Description | |
|---|---|---|---|
id | string | required | |
type | string | required | |
app_id | string | optional | |
status | string | required | |
last_error | string | optional | |
created_at | string | required | |
sip_register | object | optional | |
registrar_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | required | |
username | string | optional | |
contact_uri | string | optional | |
requested_expires_seconds | integer | required | |
granted_expires_seconds | integer | optional | |
last_registered_at | string | optional | |
next_refresh_at | string | optional | |
call_id | string | optional | |
cseq | integer | optional | |
source_address | string | optional | |
tls_insecure_skip_verify | boolean | optional | |
ip_ip | object | optional | |
peer_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | optional | |
username | string | optional | |
inbound_sources | array[string] | required | |
options_ping_interval_seconds | integer | optional | |
last_ping_at | string | optional | |
last_ping_status_code | integer | optional | |
tls_insecure_skip_verify | boolean | optional |
| Field | Type | Description | |
|---|---|---|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Remove a SIP trunk
Returns 202 Accepted; teardown and final removal run asynchronously. A sip_register trunk unregisters first (REGISTER with Expires: 0); an ip_ip trunk only stops its OPTIONS health check, and nothing is sent to the peer.
Parameters
| Name | In | Type | Description | |
|---|---|---|---|---|
id | path | string | required | Leg ID |
Responses
| Field | Type | Description | |
|---|---|---|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
Schemas
Objects used by the SIP Trunks endpoints above.
CreateTrunkRequest
| Field | Type | Description | |
|---|---|---|---|
type | enum | required | Trunk type discriminator. `sip_register` REGISTERs to an upstream registrar; `ip_ip` peers with a fixed upstream without registering. Values: sip_register, ip_ip |
app_id | string | optional | Application identifier carried through to every event emitted by this trunk. |
sip_register | object | optional | Required when type == "sip_register". Configures the outbound REGISTER (registrar URI, AOR, digest credentials, expiry). |
registrar_uri | string | required | Upstream registrar SIP URI (e.g. "sip:pbx.example.com:5060" or "sips:pbx.example.com:5061"). Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Note that "transport" is a URI parameter (";"), not a URI header ("?") — RFC 3261 section 19.1. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's REGISTER and for outbound INVITEs placed from its AOR, attached as a loose `Route` header (the Request-URI is left unchanged, and digest auth still targets `registrar_uri`). E.g. "sip:edge.example.com:5060;transport=tcp". Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `registrar_uri`. |
aor | string | required | Address-of-record this trunk REGISTERs (e.g. "sip:alice@pbx.example.com"). Becomes the From URI on outbound REGISTER, and the From / P-Asserted-Identity host on outbound INVITEs placed `from` this AOR. |
username | string | optional | Digest auth username. Defaults to the AOR user-part when empty. |
password | string | required | Digest auth password. Required. Never returned in any response. |
contact_user | string | optional | Override the user-part of the Contact header sent in REGISTER. Defaults to the AOR user-part. |
expires_seconds | integer | optional | Requested registration lifetime in seconds. Clamped to [SIP_OUTBOUND_REGISTRATION_MIN_EXPIRES_SECONDS, SIP_OUTBOUND_REGISTRATION_MAX_EXPIRES_SECONDS]. Default: SIP_OUTBOUND_REGISTRATION_DEFAULT_EXPIRES_SECONDS (3600). |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` registrar or outbound proxy whose certificate is self-signed, privately signed, or carries no SAN (`x509: certificate relies on legacy Common Name field`). Scoped to that peer's hostname — every other TLS peer is still verified in full, unlike the server-wide `SIP_TLS_INSECURE_SKIP_VERIFY`. Ignored (with a logged warning) when the next hop is not TLS, or when it is named by IP literal: such a dial sends no SNI and cannot be told apart from any other, so use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. Prefer `SIP_TLS_CA_FILE` when the peer's CA can simply be trusted. |
ip_ip | object | optional | Required when type == "ip_ip". Configures static peering with a fixed upstream (peer URI, optional digest credentials, inbound source addresses, OPTIONS health check). |
peer_uri | string | required | SIP URI of the peer (e.g. "sip:203.0.113.10:5060" or "sips:sbc.carrier.example:5061"). Outbound calls placed through this trunk are routed here: with a loose `Route` header when the call's Request-URI names another host, and with none when it already targets the peer. Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Any user part is ignored. When the host is an IP literal it is also matched against the source of inbound INVITEs. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's outbound INVITEs and OPTIONS pings. When set, the INVITE carries a single loose `Route` naming the proxy, so the peer is only reached if the call's Request-URI names it. Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `peer_uri`. A proxy is never treated as an inbound source — list its address in `inbound_sources` if the peer's calls arrive through it. |
aor | string | optional | Optional identity this trunk presents (e.g. "sip:acme@carrier.example"). An outbound call whose `from` matches it, as a full URI or by user-part, is placed through this trunk without naming `trunk_id`; its host becomes the From / P-Asserted-Identity realm when `from` names none. Also used to tell apart several trunks that share an inbound source, by the To header. |
username | string | optional | Digest auth username for outbound INVITEs the peer challenges. Requires `password`. Defaults to the `aor` user-part when a password is set. |
password | string | optional | Digest auth password for outbound INVITEs the peer challenges. Optional — omit for a peer that authenticates by source address. Never returned in any response. |
inbound_sources | array[string] | optional | IP addresses and CIDR ranges (IPv4 or IPv6) that inbound INVITEs from this peer arrive from, e.g. ["198.51.100.0/24", "203.0.113.7"]. An inbound call whose source address falls in one is tagged with this trunk's `trunk_id` and inherits its `app_id`; when several trunks match, the longest prefix wins. This is a matching rule, not an access list: calls from other addresses are still accepted. The `peer_uri` host is included automatically when it is an IP literal; hostnames are never resolved. At most 64 entries; a /0 range is rejected. |
options_ping_interval_seconds | integer | optional | Seconds between OPTIONS health checks sent to the peer; 0 (the default) disables them. With checks on, the trunk's status follows the peer — `active` when it answers, `failed` when it does not — and `sip.trunk_up` / `sip.trunk_down` are published on each change. Any reply counts as up, including 404 or 405, except 408 and 5xx other than 501; no reply within 5 seconds counts as down. With checks off the trunk stays `active`. Status is informational: calls are attempted on a `failed` trunk too. 0 |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` peer or outbound proxy whose certificate is self-signed or privately signed. Scoped to that peer's hostname — every other TLS peer is still verified in full. Ignored (with a logged warning) when the next hop is not TLS or is named by IP literal; use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. |
CreateTrunkResponse
| Field | Type | Description | |
|---|---|---|---|
id | string | required | |
type | string | required | |
status | string | required |
Error
| Field | Type | Description | |
|---|---|---|---|
instance_id | string | optional | Instance identifier |
error | string | required | Error message |
IPIPTrunkSpec
| Field | Type | Description | |
|---|---|---|---|
peer_uri | string | required | SIP URI of the peer (e.g. "sip:203.0.113.10:5060" or "sips:sbc.carrier.example:5061"). Outbound calls placed through this trunk are routed here: with a loose `Route` header when the call's Request-URI names another host, and with none when it already targets the peer. Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Any user part is ignored. When the host is an IP literal it is also matched against the source of inbound INVITEs. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's outbound INVITEs and OPTIONS pings. When set, the INVITE carries a single loose `Route` naming the proxy, so the peer is only reached if the call's Request-URI names it. Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `peer_uri`. A proxy is never treated as an inbound source — list its address in `inbound_sources` if the peer's calls arrive through it. |
aor | string | optional | Optional identity this trunk presents (e.g. "sip:acme@carrier.example"). An outbound call whose `from` matches it, as a full URI or by user-part, is placed through this trunk without naming `trunk_id`; its host becomes the From / P-Asserted-Identity realm when `from` names none. Also used to tell apart several trunks that share an inbound source, by the To header. |
username | string | optional | Digest auth username for outbound INVITEs the peer challenges. Requires `password`. Defaults to the `aor` user-part when a password is set. |
password | string | optional | Digest auth password for outbound INVITEs the peer challenges. Optional — omit for a peer that authenticates by source address. Never returned in any response. |
inbound_sources | array[string] | optional | IP addresses and CIDR ranges (IPv4 or IPv6) that inbound INVITEs from this peer arrive from, e.g. ["198.51.100.0/24", "203.0.113.7"]. An inbound call whose source address falls in one is tagged with this trunk's `trunk_id` and inherits its `app_id`; when several trunks match, the longest prefix wins. This is a matching rule, not an access list: calls from other addresses are still accepted. The `peer_uri` host is included automatically when it is an IP literal; hostnames are never resolved. At most 64 entries; a /0 range is rejected. |
options_ping_interval_seconds | integer | optional | Seconds between OPTIONS health checks sent to the peer; 0 (the default) disables them. With checks on, the trunk's status follows the peer — `active` when it answers, `failed` when it does not — and `sip.trunk_up` / `sip.trunk_down` are published on each change. Any reply counts as up, including 404 or 405, except 408 and 5xx other than 501; no reply within 5 seconds counts as down. With checks off the trunk stays `active`. Status is informational: calls are attempted on a `failed` trunk too. 0 |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` peer or outbound proxy whose certificate is self-signed or privately signed. Scoped to that peer's hostname — every other TLS peer is still verified in full. Ignored (with a logged warning) when the next hop is not TLS or is named by IP literal; use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. |
IPIPTrunkView
| Field | Type | Description | |
|---|---|---|---|
peer_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | optional | |
username | string | optional | |
inbound_sources | array[string] | required | |
options_ping_interval_seconds | integer | optional | |
last_ping_at | string | optional | |
last_ping_status_code | integer | optional | |
tls_insecure_skip_verify | boolean | optional |
SIPRegisterTrunkSpec
| Field | Type | Description | |
|---|---|---|---|
registrar_uri | string | required | Upstream registrar SIP URI (e.g. "sip:pbx.example.com:5060" or "sips:pbx.example.com:5061"). Transport is taken from the URI: a "sips:" scheme or a ";transport=tls" parameter selects TLS, ";transport=tcp" selects TCP, otherwise UDP. Note that "transport" is a URI parameter (";"), not a URI header ("?") — RFC 3261 section 19.1. |
outbound_proxy | string | optional | Next-hop SIP proxy for this trunk's REGISTER and for outbound INVITEs placed from its AOR, attached as a loose `Route` header (the Request-URI is left unchanged, and digest auth still targets `registrar_uri`). E.g. "sip:edge.example.com:5060;transport=tcp". Defaults to `SIP_OUTBOUND_PROXY`; when neither is set, requests go straight to `registrar_uri`. |
aor | string | required | Address-of-record this trunk REGISTERs (e.g. "sip:alice@pbx.example.com"). Becomes the From URI on outbound REGISTER, and the From / P-Asserted-Identity host on outbound INVITEs placed `from` this AOR. |
username | string | optional | Digest auth username. Defaults to the AOR user-part when empty. |
password | string | required | Digest auth password. Required. Never returned in any response. |
contact_user | string | optional | Override the user-part of the Contact header sent in REGISTER. Defaults to the AOR user-part. |
expires_seconds | integer | optional | Requested registration lifetime in seconds. Clamped to [SIP_OUTBOUND_REGISTRATION_MIN_EXPIRES_SECONDS, SIP_OUTBOUND_REGISTRATION_MAX_EXPIRES_SECONDS]. Default: SIP_OUTBOUND_REGISTRATION_DEFAULT_EXPIRES_SECONDS (3600). |
tls_insecure_skip_verify | boolean | optional | Accept this trunk's next-hop certificate without verifying it, for a `sips:` / `;transport=tls` registrar or outbound proxy whose certificate is self-signed, privately signed, or carries no SAN (`x509: certificate relies on legacy Common Name field`). Scoped to that peer's hostname — every other TLS peer is still verified in full, unlike the server-wide `SIP_TLS_INSECURE_SKIP_VERIFY`. Ignored (with a logged warning) when the next hop is not TLS, or when it is named by IP literal: such a dial sends no SNI and cannot be told apart from any other, so use `SIP_TLS_CA_FILE` or `SIP_TLS_INSECURE_SKIP_VERIFY` there. Prefer `SIP_TLS_CA_FILE` when the peer's CA can simply be trusted. |
SIPRegisterTrunkView
| Field | Type | Description | |
|---|---|---|---|
registrar_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | required | |
username | string | optional | |
contact_uri | string | optional | |
requested_expires_seconds | integer | required | |
granted_expires_seconds | integer | optional | |
last_registered_at | string | optional | |
next_refresh_at | string | optional | |
call_id | string | optional | |
cseq | integer | optional | |
source_address | string | optional | |
tls_insecure_skip_verify | boolean | optional |
TrunkView
| Field | Type | Description | |
|---|---|---|---|
id | string | required | |
type | string | required | |
app_id | string | optional | |
status | string | required | |
last_error | string | optional | |
created_at | string | required | |
sip_register | object | optional | |
registrar_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | required | |
username | string | optional | |
contact_uri | string | optional | |
requested_expires_seconds | integer | required | |
granted_expires_seconds | integer | optional | |
last_registered_at | string | optional | |
next_refresh_at | string | optional | |
call_id | string | optional | |
cseq | integer | optional | |
source_address | string | optional | |
tls_insecure_skip_verify | boolean | optional | |
ip_ip | object | optional | |
peer_uri | string | required | |
outbound_proxy | string | optional | |
aor | string | optional | |
username | string | optional | |
inbound_sources | array[string] | required | |
options_ping_interval_seconds | integer | optional | |
last_ping_at | string | optional | |
last_ping_status_code | integer | optional | |
tls_insecure_skip_verify | boolean | optional |
TrunksListResponse
| Field | Type | Description | |
|---|---|---|---|
trunks | array[object] | required |