SIP Trunking
Preview
SIP

Origination & Termination

How calls enter and leave the Sendexa SIP edge: map DIDs to SIP URIs for inbound service, dial out to the PSTN with authenticated trunks, configure failover, and understand CLI presentation rules.

Origination

PSTN callers dial your DID; Sendexa INVITEs your PBX or SBC at a SIP URI.

Termination

Your PBX INVITEs sip.sendexa.co with an E.164 destination; we complete to the PSTN.

Failover hunt

Primary and secondary destinations with timeouts for resilient inbound service.

CLI & attestation

Present verified caller IDs; STIR/SHAKEN on supported international routes.

Inbound

DID→SIP

Origination

Outbound

SIP→PSTN

Termination

Host

sip…

sip.sendexa.co

Numbers API

POST

/v1/sip/numbers

Call directions

Origination (inbound)

A public telephone number (DID) hosted on Sendexa rings. We receive the PSTN call and create a SIP dialog toward your infrastructure.

Caller (PSTN)
→ carrier interconnect
→ Sendexa edge
→ INVITE sip:user@your-pbx:5061
→ your IVR / queue / agent

Direction in CDR:

inbound

Termination (outbound)

An agent or application on your PBX places a call. Your system sends an authenticated SIP INVITE to Sendexa with a routable destination.

Agent / app
→ your PBX / SBC
→ INVITE sip:+233…@sip.sendexa.co
→ Sendexa + carriers
→ called party handset

Direction in CDR:

outbound

Origination — DID to SIP URI

Each DID is assigned to a trunk and given one or two destination URIs. When the number is called, Sendexa builds an INVITE with the DID as the Request-URI user (or To header, depending on profile) so your dialplan can match the called number.

POST
/v1/sip/numbers
FieldTypeRequiredDescription
numberstring
required
E.164 DID on your account, e.g. +233302123456.
trunkIdstring
required
Trunk that owns billing context and optional default destinations.
destination.primaryUristring
required
Full SIP URI. Examples: sip:233302123456@pbx.example.com:5061;transport=tls or sip:ivr@10.0.0.5:5060
destination.failoverUristringoptionalTried when primary is unreachable or times out.
destination.timeoutSecondsintegeroptionalPrimary hunt timeout before failover (default 20, max 60).
destination.headersobjectoptionalOptional custom SIP headers added to the outbound INVITE toward your PBX (e.g. X-Sendexa-DID).
Bash
curl -X POST 'https://api.sendexa.co/v1/sip/numbers' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"number": "+233302123456",
"trunkId": "TRK-8c1e2b9a-4d3f-41a0-9e7c-12ab34cd56ef",
"destination": {
"primaryUri": "sip:233302123456@pbx.example.com:5061;transport=tls",
"failoverUri": "sip:233302123456@backup.example.com:5061;transport=tls",
"timeoutSeconds": 20,
"headers": {
"X-Sendexa-Trunk": "TRK-8c1e2b9a-4d3f-41a0-9e7c-12ab34cd56ef"
}
}
}'
What your PBX receives

Typical INVITE shape (illustrative):

Bash
INVITE sip:233302123456@pbx.example.com:5061;transport=tls SIP/2.0
Via: SIP/2.0/TLS sip.sendexa.co:5061;branch=z9hG4bK...
From: <sip:+233555539152@sip.sendexa.co>;tag=...
To: <sip:+233302123456@sip.sendexa.co>
Contact: <sip:edge@sip.sendexa.co:5061;transport=tls>
Call-ID: 5f2a...@sip.sendexa.co
CSeq: 100 INVITE
Max-Forwards: 70
P-Asserted-Identity: <sip:+233555539152@sip.sendexa.co>
Content-Type: application/sdp
Content-Length: ...
v=0
o=- 0 0 IN IP4 ...
s=Sendexa SIP
c=IN IP4 ...
t=0 0
m=audio ... RTP/AVP 0 8 18 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:18 G729/8000
a=rtpmap:101 telephone-event/8000
  • From / PAI — original caller ID when available
  • To / Request-URI user — your DID (match in dialplan)
  • SDP — media toward Sendexa relay or direct as configured

Inbound failover behaviour

Primary responseNext stepCDR note
100/180/183 then 200Media established on primarydestinationUri = primary
Connection refused / TLS failImmediate failoverfailoverUsed = true
No response until timeoutFailover after timeoutSecondsfailoverUsed = true
480 / 503 / 500FailoverhangupCause may reflect final leg
486 Busy HereNo failover (subscriber busy)status = busy
404 / 484No failover (routing error on PBX)status = failed
Both failCaller cleared with network errorstatus = failed

Termination — SIP to PSTN

Outbound calls are pure SIP toward sip.sendexa.co. There is no separate REST “create call” for trunking (use the Voice API for programmable outbound). Your PBX is the call controller.

Dial string rules
FormatExampleAccepted?
E.164 with ++233555539152Yes — preferred
E.164 digits only233555539152Yes
Local leading 00555539152Maybe — if account locale set; prefer E.164
With trunk prefix9+233555539152Strip prefix on PBX before send
SIP URI usersip:+233555539152@sip.sendexa.coYes
Bash
# Request-URI examples your PBX may send
INVITE sip:+233555539152@sip.sendexa.co:5061;transport=tls SIP/2.0
INVITE sip:233555539152@sip.sendexa.co SIP/2.0
# Authorization: Digest username="cc_trunk_prod", realm="sendexa.co", ...
# From / PAI should present a DID you are allowed to use as CLI
CLI (caller ID) presentation
  • Set outbound caller ID to a Sendexa DID assigned to your account (or an explicitly authorised CLI).
  • Prefer P-Asserted-Identity and a matching From user part in E.164.
  • Unverified or spoofed CLIs may be rewritten, rejected with 403, or sent with reduced attestation.
  • Privacy: Privacy: id requests restricted presentation where the destination network supports it.

STIR / SHAKEN

Dialplan patterns

ini
[outbound-sendexa]
; 00 + country... international
exten => _00X.,1,Set(CALLERID(num)=+233302123456)
same => n,Set(CALLERID(name)=My Company)
same => n,Dial(PJSIP/+${EXTEN:2}@sendexa-endpoint,60,tT)
same => n,Hangup()
; Local Ghana mobile 0XXXXXXXXX → +233
exten => _0XXXXXXXXX,1,Set(CALLERID(num)=+233302123456)
same => n,Dial(PJSIP/+233${EXTEN:1}@sendexa-endpoint,60)
same => n,Hangup()
; Already E.164
exten => _+X.,1,Set(CALLERID(num)=+233302123456)
same => n,Dial(PJSIP/${EXTEN}@sendexa-endpoint,60)
same => n,Hangup()

Number lifecycle

Inventory
Numbers purchased or allocated via dashboard / account team appear as available DIDs.
Assign
POST /v1/sip/numbers binds a DID to a trunk and destination URIs for origination.
Reassign / release
Update destination URIs, move trunkId, or release the number back to inventory when unused.