Signals Docs
SIP Trunks

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:

PartWhat it controlsField or endpoint
DirectionWhether the trunk carries calls into your PBX, out of it, or both.direction: inbound, outbound or both
AuthenticationHow Signals recognises calls that come from your PBX.auth_mode: ip_allow_list or digest
Termination targetsWhere Signals delivers inbound calls: the SIP addresses of your PBX.targets on create, then /v1/trunks/{trunk_id}/termination-uris
MediaWhich audio codecs the trunk offers and whether audio is encrypted.codecs, media_security
LimitsHow 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 policyWhich destinations your PBX may call, spend caps and recording.outbound_policy_id on create, then PUT /v1/trunks/{trunk_id}/outbound-policy
NumbersWhich 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
SubtrunksChild configurations under one trunk, each with tighter limits./v1/trunks/{trunk_id}/subtrunks
Tests and diagnosticsChecks 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 with digest_realm, Signals generates the username and password, and the create response shows the password once as digest_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:

  • concurrency is the number of calls that may be active at the same time, inbound and outbound together.
  • cps is the number of new outbound calls that may start each second. Inbound calls are not refused for CPS.
  • max_call_duration_seconds is 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 4xx error or succeeds with 200 (201 on 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 Content and a problem detail that starts with the 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-Match returns 428 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:

StatusMeaning
enabledAdmitting new calls.
disabledNot admitting new calls.
suspendedStopped from admitting new calls with a suspend.
releasingA release was requested and the network is removing the trunk.
releasedRemoved 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}/tests with "kind": "config_validation" checks the trunk's configuration: that it has an active authentication method, termination targets where needed, and admission approval. It answers 202 Accepted; read the result from GET /v1/trunks/{trunk_id}/tests/{test_id} and its checks. The rtp_reachability and test_call kinds are part of the contract but return 422 diagnostic_test_unsupported today.
  • GET /v1/trunks/{trunk_id}/diagnostics returns 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}/metrics returns measured call outcomes for a time window.
  • The trunk's endpoint_evidence lists each termination target with its state (healthy, degraded, idle or unknown), 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:

TerminalCode
curl https://api.signals.pressone.africa/v1/platform/endpoints \ -H "Authorization: Bearer $SIGNALS_API_KEY"
JSONCode
{ "version": 1, "as_of": "2026-09-07T00:00:00Z", "signaling_fqdn": "sip.trunk.pressone.co", "signaling_nodes": ["198.51.100.10"], "signaling_ports": [ { "transport": "udp", "port": 5060 }, { "transport": "tcp", "port": 5060 }, { "transport": "tls", "port": 5061 } ], "signaling_port": 5061, "tls": { "realm": "sip.trunk.pressone.co", "trust_chain": [] }, "media_anchors": ["198.51.100.10"], "media_cidrs": ["198.51.100.10/32"], "rtp_port_range": "10000-20000", "rtp_ports": { "start": 10000, "end": 20000 } }
FieldMeaning
signaling_fqdnThe 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_nodesThe public IP addresses that send and receive SIP. Allow them in your firewall.
signaling_portsSIP over UDP and TCP on 5060, and SIP over TLS on 5061. signaling_port repeats the TLS port.
tls.realmThe TLS name of the Signals SIP service.
media_anchors, media_cidrsThe addresses audio (RTP) comes from and goes to.
rtp_portsThe 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

Last modified on