Signals Docs
SIP Trunks

Connect your PBX

Once you have created your trunk, you configure your PBX to use it. The PBX needs to know four things: where to send calls, how to prove who it is, which addresses to accept calls and audio from, and which codecs to use. This page gives those settings for Asterisk with PJSIP, FreePBX and 3CX, the firewall rules to open, and a troubleshooting guide.

The examples use the trunk from the quickstart: office-pbx, a PBX at 203.0.113.10 that accepts SIP over TLS on port 5061.

Collect your values

Read the platform values from GET /v1/platform/endpoints and the trunk values from GET /v1/trunks/{trunk_id}. Do not copy the values below into production without checking them against the API: PressOne can change platform addresses, and the response's version and as_of tell you when.

SettingExample valueWhere it comes from
SIP serversip.trunk.pressone.cosignaling_fqdn in platform endpoints
Trunk SIP domainoffice-pbx.sip.trunk.pressone.cosignaling_fqdn on the trunk
Signalling addressesThe addresses in signaling_nodessignaling_nodes
SIP ports5061 for TLS, 5060 for UDP or TCPsignaling_ports
TLS namesip.trunk.pressone.cotls.realm
Media addressesThe ranges in media_cidrsmedia_cidrs
Signals RTP portsUDP 10000 to 20000rtp_ports
CodecsG.711 A-law (PCMA) and mu-law (PCMU), 20 ms, plus any of G729, G722 and OPUS you addedcodecs on the trunk; G.711 is always offered
DTMFRFC 4733 telephone events
Number formatE.164 with a leading +, for example +2348034128890
Caller IDA number routed to the trunk, for example +2342013300100Numbers and routing
AuthenticationYour PBX's public address, or a digest username, password and realmAuthentication and security

Open your firewall

Your firewall must let SIP and audio pass between your PBX and Signals. TLS runs over TCP, so the TLS port is a TCP port.

DirectionProtocol and portsFromToWhy
OutTCP 5061 (TLS), or UDP and TCP 5060Your PBXsignaling_nodesYour PBX sends calls to Signals.
InThe port in your termination target, such as TCP 5061signaling_nodesYour PBXSignals delivers inbound calls.
OutUDP, your PBX's RTP portsYour PBXmedia_cidrs, UDP 10000 to 20000Audio to Signals.
InUDP 10000 to 20000 from Signals, to your PBX's RTP portsmedia_cidrsYour PBXAudio from Signals.

UDP 10000 to 20000 is the range of ports Signals sends audio from and receives audio on, so it is the range to allow from the Signals media address. It does not limit how many calls you can run. Concurrency is set by your trunk and outbound policy limits.

If your PBX sits behind NAT, it must advertise its public address in SIP and SDP, and keep audio flowing through itself rather than directly between phones and Signals. The settings below cover both.

Asterisk with PJSIP

These settings target Asterisk 18 or later with chan_pjsip. They define a TLS transport, the Signals endpoint, its address of record (AOR) and an identify section that matches calls coming from Signals.

IP allow list trunk

Add this to pjsip.conf. Replace the certificate paths and 203.0.113.10 with your own:

Code
; Signals trunk office-pbx over TLS, IP allow list authentication. [signals-tls] type = transport protocol = tls bind = 0.0.0.0:5061 cert_file = /etc/asterisk/keys/pbx.example.com.ng.crt priv_key_file = /etc/asterisk/keys/pbx.example.com.ng.key method = tlsv1_2 external_signaling_address = 203.0.113.10 external_media_address = 203.0.113.10 [signals] type = endpoint transport = signals-tls context = from-signals aors = signals disallow = all allow = alaw,ulaw dtmf_mode = rfc4733 direct_media = no rtp_symmetric = yes force_rport = yes rewrite_contact = yes from_domain = office-pbx.sip.trunk.pressone.co [signals] type = aor contact = sip:sip.trunk.pressone.co:5061 [signals] type = identify endpoint = signals match = 198.51.100.10/32 ; each range in media_cidrs and signaling_nodes
  • bind = 0.0.0.0:5061 with your certificate lets Signals deliver inbound calls over TLS, matching the tls termination target.
  • direct_media = no keeps audio on the PBX, which NAT and the Signals media address require.
  • identify with match tells Asterisk that SIP from the Signals signalling address belongs to this endpoint. Add one match line per address in signaling_nodes.
  • There is no registration. Signals reaches your PBX through the termination targets on the trunk.

If your trunk does not require TLS, use a UDP transport on port 5060 instead and set contact = sip:sip.trunk.pressone.co:5060.

Digest trunk

For a digest trunk, add an auth section with the credential Signals generated, and point the endpoint at it with outbound_auth. Keep the transport, AOR and identify sections from above:

Code
[signals-auth] type = auth auth_type = userpass username = sig_01992f3a91b07c558e214a6d0f3b9c18 password = PASTE_THE_PASSWORD_SHOWN_ONCE realm = sip.trunk.pressone.co [signals] type = endpoint transport = signals-tls context = from-signals aors = signals outbound_auth = signals-auth disallow = all allow = alaw,ulaw dtmf_mode = rfc4733 direct_media = no rtp_symmetric = yes force_rport = yes rewrite_contact = yes from_domain = office-pbx.sip.trunk.pressone.co

When you rotate the credential, replace username and password and run pjsip reload before the old credential's previous_retires_at.

Encrypted audio

If the trunk uses "media_security": "sdes_srtp_required", add this line to the endpoint:

Code
media_encryption = sdes

Use it only with the TLS transport. SDES sends the audio keys inside SIP messages.

Dialplan

Send outbound calls in E.164 format with a caller ID routed to the trunk. This example also turns a Nigerian national number such as 08034128890 into +2348034128890:

Code
[to-signals] exten => _+X.,1,Set(CALLERID(num)=+2342013300100) same => n,Dial(PJSIP/${EXTEN}@signals,60) same => n,Hangup() exten => _0XXXXXXXXXX,1,Set(CALLERID(num)=+2342013300100) same => n,Dial(PJSIP/+234${EXTEN:1}@signals,60) same => n,Hangup()

Inbound calls arrive in the from-signals context with the called number in the request URI. This example rings extension 1001 for any number. Place a test call and check the Asterisk console for the exact format of the called number, then match it per number:

Code
[from-signals] exten => _X.,1,Dial(PJSIP/1001,30) same => n,Hangup() exten => _+X.,1,Dial(PJSIP/1001,30) same => n,Hangup()

FreePBX

FreePBX builds the same PJSIP configuration from its web interface. Menu and field names below follow recent FreePBX releases and may differ in yours.

  1. In Settings, open the SIP settings for chan_pjsip. Set your external (public) address and your local networks so FreePBX rewrites addresses behind NAT. If your trunk requires TLS, enable the TLS transport on port 5061 with a certificate from the certificate manager.
  2. In Connectivity, add a PJSIP trunk named signals.
  3. On the trunk's general settings, set the outbound caller ID to a routed number, such as +2342013300100.
  4. On the PJSIP settings:
    • Set the SIP server to sip.trunk.pressone.co and the port to 5061 for TLS, or 5060 for UDP.
    • Choose the transport that matches the port.
    • Turn registration off.
    • For an IP allow list trunk, set authentication to none. For a digest trunk, set outbound authentication with the username and password Signals generated.
    • Set the inbound context to your inbound routes context (FreePBX uses from-pstn).
  5. On the advanced PJSIP settings, set the match or permit address to the ranges in signaling_nodes and media_cidrs, turn direct media off, turn RTP symmetric and rewrite contact on, and set the from domain to the trunk's signaling_fqdn. If the trunk requires SRTP, set media encryption to SDES (SRTP via in-SDP).
  6. On the codecs tab, allow only alaw and ulaw.
  7. Create an outbound route that sends numbers in E.164 format through the signals trunk. Add a dial pattern that prefixes +234 and strips the leading 0 from national numbers.
  8. Create inbound routes for the numbers you routed to the trunk.
  9. Apply the configuration.

3CX

3CX menu names change between versions, so this section lists the settings rather than the exact screens. Add a SIP trunk using a generic SIP trunk template, then set:

3CX settingValue
Registrar, server or proxysip.trunk.pressone.co
Port5061 for TLS, 5060 for UDP or TCP
TransportTLS if your 3CX version offers it for SIP trunks; otherwise UDP, with require_tls set to false on the trunk
AuthenticationIP-based (no registration) for an IP allow list trunk; username and password for a digest trunk
Authentication ID and passwordThe digest username and password, for digest trunks only
Main trunk numberA number routed to the trunk, such as +2342013300100
Allowed codecsG.711 A-law and G.711 U-law only
Outbound caller IDA number routed to the trunk

Then create outbound rules that send calls through the trunk in E.164 format with a +, and inbound rules (DID rules) for each routed number or range. Allow the Signals signalling and media addresses in any firewall in front of 3CX, as listed in Open your firewall.

If your 3CX cannot use TLS for SIP trunks, create the trunk with "require_tls": false, a udp or tcp termination target, and "media_security": "rtp". SRTP with SDES is not safe without TLS.

Verify the connection

  1. Wait a minute after your last change so it has taken effect.
  2. Run a configuration test: POST /v1/trunks/{trunk_id}/tests with { "kind": "config_validation" }, then read the test.
  3. Place an outbound call to a Nigerian mobile number from an extension.
  4. Call one of your routed numbers from a mobile phone and confirm it rings the PBX.
  5. Check GET /v1/trunks/{trunk_id}/diagnostics and the trunk's endpoint_evidence after a few calls.

Troubleshooting

Start with the API. It tells you how the trunk is configured and what the network saw on real calls.

Outbound calls are rejected before they ring

  • The change is very recent. A saved change takes effect within a minute. If a change cannot be applied, PressOne staff are alerted and the previous configuration keeps serving, so a call can still follow your earlier settings for a short time.
  • Your address is not allowed. Calls must come from an address in the trunk's IP allow list. Behind NAT, your traffic may leave from a different public address than you expect. Compare it with GET /v1/trunks/{trunk_id}/ip-credentials.
  • Digest fails. Check the username, password and realm. A new credential works once the network has accepted it (new_applied_at is set), within a minute. A rotated credential stops at previous_retires_at, and a revoked one stops within a minute of the revoke.
  • TLS fails. Confirm the PBX connects to port 5061 over TLS and trusts the Signals certificate.

Outbound calls are refused after authentication

  • No policy. The trunk's policy must be set. A trunk without a policy refuses every outbound call.
  • Destination not allowed. The number must match an allow rule in the policy, and no more specific deny rule. Send numbers in E.164 format.
  • Caller ID not allowed. The caller ID must be a number routed to the trunk, with its route status applied. A trunk's numbers count of 0 means it has none.
  • A limit was reached. Check concurrency, cps and the daily spend cap on the trunk, the policy and any subtrunk. ceilings.daily_spend.used_today_minor on the policy shows today's spend.
  • The trunk is suspended. status is suspended. Call POST /v1/trunks/{trunk_id}/resume.

Inbound calls do not arrive

  • The route is not applied. GET /v1/numbers/blocks/{block_id}/routes should show the number's slice with the trunk as its effective target and status applied.
  • The trunk does not take inbound calls. Its direction must be inbound or both, with at least one enabled termination target.
  • Signals cannot reach your PBX. Allow SIP from the Signals signalling address to the port in your termination target. For a tls target, your PBX needs a valid certificate on that port.
  • Target health. The trunk's endpoint_evidence shows each target as healthy, degraded, idle or unknown, with the last failure code. Signals does not probe targets, so a target shows idle until real calls reach it.

One-way audio or no audio

  • Allow UDP in both directions between your PBX's RTP ports and the Signals media address on ports 10000 to 20000.
  • Set your public address for media (external_media_address in Asterisk) and keep direct media off.
  • GET /v1/trunks/{trunk_id}/diagnostics counts one_way_calls and no_media_calls over the last 24 hours, alongside MOS, packet loss and jitter.

Calls fail when the trunk requires SRTP

With "media_security": "sdes_srtp_required", your PBX must offer SRTP with SDES keys. In Asterisk, set media_encryption = sdes on the endpoint and use the TLS transport.

Calls end at the same length every time

A call ends when it reaches max_call_duration_seconds. The shortest value across the trunk, the policy and any subtrunk applies.

Contacting support

Every API error is an application/problem+json body with a code and a request_id, and every response carries an X-Request-ID header. Include the request ID, the trunk ID and the time of the call when you contact PressOne support.

Last modified on