Authentication and security
Before Signals carries a call from your PBX, it must be sure the call really comes from you. Otherwise anyone who found your trunk could place calls on your account. This page explains the two ways a trunk recognises your PBX, how to manage credentials safely, and how to protect signalling and audio in transit.
Every change on this page is live once the API accepts it and takes effect within a minute. There is
nothing to publish. Each edit needs the trunk's current ETag in If-Match and returns a new one.
See Saving changes.
Choose an authentication mode
A trunk uses one mode, set by auth_mode when you create it and changeable with
PATCH /v1/trunks/{trunk_id}:
IP allow list (ip_allow_list) | Digest (digest) | |
|---|---|---|
| How Signals recognises you | The public IP address the call comes from. | A username and password your PBX sends when Signals challenges it. |
| Best for | A PBX or session border controller with a fixed public IP address. | A PBX behind a changing address, or several sites sharing one trunk. |
| What you manage | A list of addresses and ranges. | Generated credentials, rotated on a schedule. |
| Secret to protect | None. | The password, shown once. |
When you can, prefer an IP allow list with TLS. There is no password to leak, and a call from any other address is refused.
IP allow lists
An IP allow list is the set of public addresses Signals accepts calls from. Each entry is an IP
credential: a CIDR range, such as 203.0.113.10/32 for one address or 203.0.113.0/28 for sixteen.
Set the list when you create the trunk
Pass the addresses in sources with "auth_mode": "ip_allow_list". The list must not be empty.
Each entry must be a public IPv4 address or range. Private ranges such as 10.0.0.0/8 and
192.168.0.0/16, loopback, link-local, multicast and broadcast addresses are refused with
422 invalid_trunk.
Code
Add, change and remove addresses
Manage the list afterwards with the IP credential endpoints:
| Action | Request |
|---|---|
| List | GET /v1/trunks/{trunk_id}/ip-credentials |
| Add | POST /v1/trunks/{trunk_id}/ip-credentials with If-Match and Idempotency-Key |
| Change | PATCH /v1/trunks/{trunk_id}/ip-credentials/{credential_id} with If-Match |
| Remove | DELETE /v1/trunks/{trunk_id}/ip-credentials/{credential_id} with If-Match |
An add or change takes a body like this:
Code
cidrmust include the prefix length, for example/32.selector_precedencedecides which entry wins when ranges overlap. It defaults to100.enabledlets you switch an entry off without deleting it. It defaults totrue.
Two enabled entries on the same trunk cannot overlap at the same selector_precedence, and the same
range cannot appear twice. Either returns 409 trunk_component_conflict.
When you replace a PBX address, add the new address first and remove the old one a minute later. Calls from an address that is not on the list are refused.
Digest credentials
Digest authentication is a challenge and response. Signals challenges a call from your PBX, and the PBX answers with a username and a value derived from the password. The password itself never crosses the network. Signals stores only that derived value (HA1), so it cannot show you the password again later.
Create a digest trunk
Create the trunk with "auth_mode": "digest", an empty sources list and a digest_realm, the
name of the authentication domain your PBX answers for. Sending addresses with digest returns
422 invalid_trunk, and so does leaving out digest_realm.
Code
Signals creates the trunk's first credential in the same request. The 201 Created body is
{ "trunk": { ... }, "digest_password": "..." }. The username is in the trunk's
authentication.digest. Copy the password now: this is the only response that contains it, and a
replay of the same request returns "digest_password": null.
Create another credential
To add a credential to an existing trunk, for example for a second PBX, create one. Signals generates the username and password. You choose only the realm, the name of the
authentication domain your PBX answers for. The realm must be 1 to 255 characters with no spaces or
colons. The console uses the platform realm sip.trunk.pressone.co from tls.realm in
GET /v1/platform/endpoints.
Code
Code
Copy the password into your PBX or a secrets manager now. This is the only response that contains it.
The password is shown once
GET /v1/trunks/{trunk_id}/digest-credentialsreturns usernames and lifecycle dates, never the password or HA1.- If your request times out and you retry it with the same
Idempotency-Key, you get the same credential back with"password": nulland"secret_unavailable": true. The password is never disclosed twice. - If you lose a password, rotate the credential or revoke it and create a new one.
A digest trunk must keep at least one enabled credential. A change that would leave it with none
returns 422 with a detail that starts with the trunk would not apply:.
Rotate with overlap
Rotation replaces a credential without dropping calls. Signals creates a new username and password and keeps the old credential valid for 24 hours after the network has applied the new one. That overlap gives you a day to update every PBX.
-
Rotate the credential. The response contains the new password, once:
CodeCode -
Within a minute the network accepts the new credential. Its
new_applied_atis then set, andprevious_retires_atshows when the old credential stops working, 24 hours later. -
Update each PBX with the new username and password before
previous_retires_at.
Revoke a credential
DELETE /v1/trunks/{trunk_id}/digest-credentials/{credential_id} with If-Match revokes the
credential and returns 204 No Content. The network stops accepting it within a minute.
TLS for signalling
SIP messages carry phone numbers, caller IDs and, with digest, authentication exchanges. TLS
encrypts them between your PBX and Signals. Signals accepts SIP over TLS on port 5061 at the
signalling address in GET /v1/platform/endpoints, and over UDP or TCP on port 5060.
Set require_tls to true to keep a trunk on TLS. With require_tls on, every termination target
must use "transport": "tls", so Signals reaches your PBX over TLS too. A target with udp or
tcp returns 422 invalid_trunk. A target written as a sips: URI must always use tls.
Code
Point your PBX at port 5061 with TLS, and verify the Signals certificate. The tls object in the
platform endpoints response gives the TLS name (realm) and any certificate chain information
(trust_chain).
Source validation
source_validation takes relaxed or strict. strict also checks the SIP Via header against
your allowed sources, so a request has to come from, and claim to come from, an address you listed.
Use strict with an IP allow list. Keep relaxed with digest, where your PBX address may change.
Media security
Audio travels as RTP, separately from SIP. Two settings control it.
media_security decides whether audio is encrypted:
| Value | What happens |
|---|---|
rtp | Audio is plain RTP. |
sdes_srtp_required | Audio must be SRTP, encrypted with keys exchanged in the SDP (SDES). A call that does not negotiate SRTP is refused rather than downgraded to plain RTP. |
SDES keys travel inside the SIP messages, so SRTP only protects audio when signalling is also
encrypted. Pair sdes_srtp_required with require_tls: true and a TLS connection from your PBX.
codecs decides which audio codecs the trunk offers. G.711 (PCMA and PCMU) is always on; add
G729, G722 or OPUS to turn those on too. A repeated codec is refused. Signals offers them to
your PBX in a fixed order, OPUS, G722, G729, PCMA, PCMU, whatever order you send.
Audio flows through the Signals media address in media_cidrs. Your PBX never exchanges audio
directly with the far end.
Limits as a safety control
Limits stop a compromised PBX or a dialling loop from running up cost:
- On the trunk:
concurrency,cpsandmax_call_duration_seconds. - On the outbound policy: the same three, plus
max_destination_rate_minoranddaily_spend_limit_minor. See Outbound policies.
Signals applies every limit that covers a call, and the tightest wins.
Checklist
- Use an IP allow list with
strictsource validation when your PBX has a fixed public address. - Turn on
require_tlsand connect on port 5061. - Use
sdes_srtp_requiredwhen audio must be encrypted. - Store digest passwords in a secrets manager, never in tickets or chat.
- Rotate digest credentials on a schedule.
- Set a daily spend cap on every outbound policy.