Trunk Configuration
Deep configuration for enterprise SIP trunks: edge endpoints, authentication, codecs, capacity, failover, security hardening, and production-ready PBX snippets.
UDP · TCP · TLS
Signal on 5060 (UDP/TCP) or 5061 (TLS). Production should default to TLS.
Codec control
Allowlist G.711, G.729, and Opus; order sets SDP preference.
Digest + IP ACL
Layer credentials with CIDR allowlists to stop credential stuffing.
HA failover
Primary and secondary origination URIs with configurable hunt timeout.
sip…
sip.sendexa.co
5060
Standard SIP
5061
Recommended
sendexa
sendexa.co
Authentication
Authorization: Basic <token>. Auth guide →SIP edge reference
| Parameter | Value | Guidance |
|---|---|---|
| SIP host | sip.sendexa.co | Use the hostname (not a pinned IP) for multi-region HA |
| Port UDP | 5060 | Common for legacy PBXes; less preferred on public internet |
| Port TCP | 5060 | Better through strict NAT/firewall than UDP |
| Port TLS | 5061 | Encrypts signaling; required for SRTP-only policies |
| Supported methods | INVITE, ACK, BYE, CANCEL, OPTIONS, REGISTER, UPDATE, PRACK, REFER* | *REFER / transfers on selected plans |
| Session timers | RFC 4028 | Default session-expires ~1800s; refresh with UPDATE/re-INVITE |
| OPTIONS keepalive | Supported | Responds to OPTIONS for trunk health probes |
Authentication modes
Every INVITE and REGISTER toward Sendexa must authenticate. You can combine methods for defence in depth.
Standard HTTP Digest authentication (RFC 3261 / RFC 2617 style) with realm sendexa.co.
- Username and password set at
POST /v1/sip/trunks - Challenge returned as SIP 401 with WWW-Authenticate
- PBX must retry INVITE with Authorization header
- Password rotatable without changing trunkId
When ipAllowlist is non-empty, signaling from other source addresses is rejected with 403 before digest is even evaluated (or after failed match — treat ACL as hard gate).
- CIDR notation: /32 for single host, /24 for subnet
- Include all SBC egress IPs and HA peers
- Update ACL before changing datacentre IPs
- Empty list = any IP may attempt digest (weaker)
Do not share trunk credentials across environments
Codecs & media
| Codec | SDP name | Bitrate | Use case |
|---|---|---|---|
| G.711 µ-law | PCMU / ulaw | ~64 kbps | Default PSTN interoperability (Americas) |
| G.711 A-law | PCMA / alaw | ~64 kbps | Default PSTN interoperability (EU/Africa) |
| G.729 | G729 | ~8 kbps | Bandwidth-constrained WAN / many concurrent calls |
| Opus | opus | variable | Wideband quality where both legs support it |
Codec lists on the trunk act as an allowlist. Negotiation follows SDP offer/answer: if there is no intersection with the far end, Sendexa returns 488 Not Acceptable Here. Prefer listing PCMU and PCMA first for maximum PSTN compatibility, then G.729 / Opus.
When using TLS signaling, you may enable SDES-SRTP on your PBX. Sendexa supports optional SRTP on eligible trunks. If your endpoint requires encryption but the PSTN leg cannot, media is decrypted at the Sendexa edge before carrier handoff.
DTMF: use RFC 2833 / telephone-event (payload type negotiated in SDP). In-band DTMF is unreliable with compressed codecs.
Capacity & concurrency
| Field | Type | Required | Description |
|---|---|---|---|
| maxConcurrentCalls | integer | optional | Hard cap of simultaneous sessions (inbound + outbound) on the trunk. Excess INVITEs receive 486 or 503. |
| activeCalls | integer | optional | Read-only gauge returned on GET trunk detail — current established + early dialogs. |
| cpsHint | integer | optional | Soft guidance for calls-per-second. Sustained bursts may be rate-shaped; contact support for high CPS. |
Sizing tip
maxConcurrentCalls to peak busy-hour agents × concurrency factor (often 1.1–1.3), not seat count alone. Track utilisation from CDR and live activeCalls.Origination failover
For inbound (DID → your infrastructure), configure two destinations. Sendexa hunts primary first, then failover.
| Condition | Action |
|---|---|
| Primary returns 18x then 200 OK | Call stays on primary |
| Primary TCP/TLS connect failure | Immediate try of failover URI |
| Primary timeout (no provisional) | After timeoutSeconds → failover |
| Primary 480 / 503 / 500 | Failover URI attempted |
| Primary 486 Busy | No failover by default (true busy) |
| Both destinations fail | Caller hears network busy / 503 |
{"origination": {"primaryUri": "sip:inbound@pbx-a.example.com:5061;transport=tls","failoverUri": "sip:inbound@pbx-b.example.com:5061;transport=tls","timeoutSeconds": 20}}
Update a trunk via REST
Create uses POST /v1/sip/trunks. Listing uses GET /v1/sip/trunks. Partial updates (password rotate, ACL, codecs) use the trunk resource:
# Rotate password and tighten ACLcurl -X PATCH 'https://api.sendexa.co/v1/sip/trunks/TRK-8c1e2b9a-4d3f-41a0-9e7c-12ab34cd56ef' \-H 'Content-Type: application/json' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-d '{"auth": { "password": "New-Long-Secret-2026!" },"ipAllowlist": ["203.0.113.10/32", "203.0.113.11/32"],"codecs": ["PCMU", "PCMA", "G729"],"maxConcurrentCalls": 50}'
Production PBX / SBC examples
; /etc/asterisk/pjsip_sendexa.conf; Include from pjsip.conf: #include pjsip_sendexa.conf[transport-tls]type=transportprotocol=tlsbind=0.0.0.0:5061cert_file=/etc/asterisk/keys/asterisk.crtpriv_key_file=/etc/asterisk/keys/asterisk.keymethod=tlsv1_2[sendexa-auth]type=authauth_type=userpassusername=cc_trunk_prodpassword=S3cure-Long-Secret!realm=sendexa.co[sendexa-aor]type=aorcontact=sip:sip.sendexa.co:5061;transport=tlsqualify_frequency=30qualify_timeout=3.0max_contacts=1[sendexa-endpoint]type=endpointcontext=from-sendexadisallow=allallow=ulaw,alaw,g729,opusoutbound_auth=sendexa-authaors=sendexa-aorfrom_user=cc_trunk_prodfrom_domain=sendexa.codirect_media=nortp_symmetric=yesforce_rport=yesrewrite_contact=yesice_support=nomedia_encryption=sdesmedia_encryption_optimistic=yestimers=yestimers_min_se=90timers_sess_expires=1800dtmf_mode=rfc4733transport=transport-tlstrust_id_inbound=yessend_pai=yessend_rpid=yes[sendexa-identify]type=identifyendpoint=sendexa-endpointmatch=sip.sendexa.co[sendexa-reg]type=registrationtransport=transport-tlsoutbound_auth=sendexa-authserver_uri=sip:sip.sendexa.co:5061;transport=tlsclient_uri=sip:cc_trunk_prod@sendexa.cocontact_user=cc_trunk_prodretry_interval=60forbidden_retry_interval=300expiration=600line=yesendpoint=sendexa-endpoint
; Outbound: dial 9 + E.164 or national → Sendexa[to-sendexa]exten => _9.,1,NoOp(Outbound via Sendexa ${EXTEN:1})same => n,Set(CALLERID(num)=+233302123456)same => n,Dial(PJSIP/${FILTER(0123456789+,${EXTEN:1})}@sendexa-endpoint,60)same => n,Hangup(); Inbound from Sendexa DIDs[from-sendexa]exten => _X.,1,NoOp(Inbound DID ${EXTEN} from ${CALLERID(all)})same => n,Goto(ivr-main,s,1)
Security hardening
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 loops | Wrong password/realm or not answering challenge | Verify username, password, realm=sendexa.co |
| 403 on every INVITE | Source IP not in ACL | Add egress public IP as /32; check NAT |
| 488 codec | Only Opus offered but trunk allowlist is G.711-only | Align codecs array and PBX allow list |
| One-way audio | NAT / direct media | direct_media=no, rtp_symmetric, open RTP ports |
| Inbound never rings | Wrong destination URI or firewall | Check DID primaryUri, OPTIONS/INVITE reachability |
| 486 at peak | maxConcurrentCalls exhausted | Raise limit or add trunks; check stuck calls |