SIP Trunks overview
A SIP trunk is a phone line for your phone system that runs over the internet instead of copper. Your office phone system, called a PBX (private branch exchange), sends and receives calls using SIP, the signalling protocol most IP phone systems speak. A trunk connects that PBX to Signals, and Signals connects it to the public phone network in Nigeria and beyond.
You keep your PBX, your extensions and your call flows. Signals carries the calls between your PBX and the outside world, enforces the limits you set, and tells you what happened to each call.
What an Intelligent SIP Trunk is on Signals
On Signals, a trunk is a configuration object you create with the API or the console. It describes
how your PBX connects and what it is allowed to do. Each trunk has an ID that starts with trk_,
for example trk_01992f3a-6c1e-7d42-9b8a-5e7f0c2d1a94.
A trunk brings together these parts:
| Part | What it controls | Field or endpoint |
|---|---|---|
| Direction | Whether the trunk carries calls into your PBX, out of it, or both. | direction: inbound, outbound or both |
| Authentication | How Signals recognises calls that come from your PBX. | auth_mode: ip_allow_list or digest |
| Termination targets | Where Signals delivers inbound calls: the SIP addresses of your PBX. | targets on create, then /v1/trunks/{trunk_id}/termination-uris |
| Media | Which audio codecs the trunk offers and whether audio is encrypted. | codecs, media_security |
| Limits | How many calls run at once, how fast new calls start, and how long a call may last. | limits.concurrency, limits.cps, limits.max_call_duration_seconds |
| Outbound policy | Which destinations your PBX may call, spend caps and recording. | outbound_policy_id on create, then PUT /v1/trunks/{trunk_id}/outbound-policy |
| Numbers | Which phone numbers ring this trunk, and which numbers it may use as caller ID. | number_block_ids on create, then block routes under /v1/numbers/blocks |
| Subtrunks | Child configurations under one trunk, each with tighter limits. | /v1/trunks/{trunk_id}/subtrunks |
| Tests and diagnostics | Checks that the trunk's configuration is complete, and evidence from real calls. | /v1/trunks/{trunk_id}/tests, /diagnostics, /metrics |
Direction
An inbound trunk receives calls to your numbers and delivers them to your PBX. An outbound
trunk lets your PBX place calls to the phone network. A both trunk does both. A trunk that takes
inbound calls (inbound or both) needs at least one termination target, or the API refuses it.
Authentication
Signals must know that a call really comes from your PBX before it carries it. You choose one of two methods per trunk:
- IP allow list (
ip_allow_list): Signals accepts calls from the public IP addresses you list. - Digest (
digest): your PBX answers a username and password challenge. You choose the realm withdigest_realm, Signals generates the username and password, and the create response shows the password once asdigest_password.
Authentication and security explains both, along with TLS and encrypted media.
Termination targets
A termination target is a SIP address of your PBX, such as sip:203.0.113.10:5061, with a
transport (udp, tcp or tls), a priority and a weight. Signals tries targets with the
lowest priority value first. Targets that share a priority split calls by weight. Signals does
not probe your targets with SIP OPTIONS; it judges target health from real call attempts.
Media
codecs lists the audio codecs the trunk offers: PCMA, PCMU, G729, G722 and OPUS. G.711
(PCMA and PCMU) is always on; add the others you want. Signals offers them in a fixed order
(OPUS, G722, G729, PCMA, PCMU), so the order you send does not matter. A codec may appear only once.
The media security setting decides whether audio is encrypted: rtp sends plain RTP, and
sdes_srtp_required requires SRTP. In both cases audio flows through the Signals media address
listed under platform endpoints.
Limits
Limits protect you from runaway traffic and unexpected cost:
concurrencyis the number of calls that may be active at the same time, inbound and outbound together.cpsis the number of new outbound calls that may start each second. Inbound calls are not refused for CPS.max_call_duration_secondsis the longest a single call may last.
If you omit limits when you create a trunk, Signals uses 100 concurrent calls, 10 calls per second
and 7,200 seconds (two hours). Signals checks limits at every level that applies to a call: your
organization, the subaccount if there is one, the trunk, and the outbound policy. The tightest
limit wins.
Outbound policy
An outbound policy is a named, reusable set of rules for outbound calls: which countries and
prefixes your PBX may call, spend caps and recording. You attach one policy to a trunk, either in
the create request with outbound_policy_id or later. A change to the policy reaches every trunk
that uses it within a minute. A trunk without a policy refuses every outbound call. See
Outbound policies.
Numbers
You buy phone numbers in contiguous blocks and route them, or slices of them, to a trunk. Calls to those numbers arrive on the trunk. The numbers routed to a trunk are also the caller IDs it may present on outbound calls. See Numbers and routing.
Saving changes
Every change you make is live once the API accepts it. There is no draft to publish.
- Validation happens at the save. Creating or editing a trunk, a credential, a termination
target or a policy either fails with a
4xxerror or succeeds with200(201on create) and the resource as stored. - A change that would leave the trunk unable to run is refused. For example, an invalid
inbound URI, an invalid source list, or limits above your organization's limits fail with
422 Unprocessable Contentand a problem detail that starts withthe trunk would not apply:. - Signals applies accepted changes to the network for you. Changes take effect within a minute. If a change cannot be applied, PressOne staff are alerted and the previous configuration keeps serving. You do not wait for it or poll for it.
Revisions and ETags
Each trunk has a revision, an integer that goes up with every saved change. Responses carry it in
the ETag header as a quoted integer, for example "3". Edits require that value in an If-Match
header, so two people cannot overwrite each other's changes:
- A missing
If-Matchreturns428 Precondition Required. - A value that no longer matches returns
412 Precondition Failed. Read the trunk again to get the current ETag. - A malformed value returns
400 Bad Request.
The revision is only a concurrency token. See Requests and errors for the general rules.
Trunk status
The status field tells you where a trunk is in its life:
| Status | Meaning |
|---|---|
enabled | Admitting new calls. |
disabled | Not admitting new calls. |
suspended | Stopped from admitting new calls with a suspend. |
releasing | A release was requested and the network is removing the trunk. |
released | Removed from the network. |
POST /v1/trunks/{trunk_id}/suspend stops new calls within a minute. Calls already in progress
continue. POST /v1/trunks/{trunk_id}/resume allows new calls again.
DELETE /v1/trunks/{trunk_id} releases a trunk. You confirm the exact trunk name in the body. The
API refuses with 409 if the trunk still has active calls (trunk_not_drained) or still has routes,
subtrunks or policies attached (trunk_referenced).
Tests and diagnostics
POST /v1/trunks/{trunk_id}/testswith"kind": "config_validation"checks the trunk's configuration: that it has an active authentication method, termination targets where needed, and admission approval. It answers202 Accepted; read the result fromGET /v1/trunks/{trunk_id}/tests/{test_id}and itschecks. Thertp_reachabilityandtest_callkinds are part of the contract but return422 diagnostic_test_unsupportedtoday.GET /v1/trunks/{trunk_id}/diagnosticsreturns audio quality measured on real calls over the last 24 hours: MOS, packet loss, jitter, and counts of one-way-audio and no-audio calls.GET /v1/trunks/{trunk_id}/metricsreturns measured call outcomes for a time window.- The trunk's
endpoint_evidencelists each termination target with its state (healthy,degraded,idleorunknown), based only on call attempts in the last 24 hours.
Platform endpoints
Your PBX needs the public addresses of Signals: where to send SIP, which ports to use, and which address audio comes from. Read them from the API rather than hard-coding them:
Code
Code
| Field | Meaning |
|---|---|
signaling_fqdn | The Signals SIP domain. Each trunk also gets its own name under it in the trunk's signaling_fqdn, for example office-pbx.sip.trunk.pressone.co. |
signaling_nodes | The public IP addresses that send and receive SIP. Allow them in your firewall. |
signaling_ports | SIP over UDP and TCP on 5060, and SIP over TLS on 5061. signaling_port repeats the TLS port. |
tls.realm | The TLS name of the Signals SIP service. |
media_anchors, media_cidrs | The addresses audio (RTP) comes from and goes to. |
rtp_ports | The UDP ports Signals uses for audio, 10000 to 20000. |
The RTP port range is the set of UDP ports to allow in your firewall for audio from the Signals media address. It is not a limit on how many calls you can run. Concurrency is set by your trunk and outbound policy limits.
The version and as_of fields change when PressOne updates these values. Check them when you
plan firewall changes.
Who can do what
API keys and console users carry a role. Admin and engineer roles can create and edit trunks, policies and number routes. The viewer role can read trunks and policies. See Authentication.
Next steps
- Quickstart: create and test a trunk with curl.
- Connect your PBX: settings for Asterisk, FreePBX and 3CX.
- SIP Trunking API reference and Platform API reference.