iPhone not ringing? Every fix
Almost every 'it doesn't ring' has one of five causes, and the relay tells you which in its response. Test the wake path from a terminal first; the PBX is innocent until curl says otherwise.
Start here: the two-second test
Lock your phone. From any machine, send a fake wake with the values your app is really configured with:
curl -s -w "\n%{http_code}\n" https://sipreg.saffronsuite.com/v1/incoming-call \
-H "Authorization: Bearer pk_your_key_from_the_app" \
-H "Content-Type: application/json" \
-d '{"call_id":"test-'$RANDOM'","to":"sip:101@pbx.example.com","from":"100","display_name":"Test"}'Phone rings and you see 202: the wake path is healthy, skip to the PBX-side section. Otherwise, find your code below.
404 no_active_devices: the big one
The relay couldn't find an enrolled phone matching your to value. It matches exactly against what the app registered:
app Settings → Account your webhook must send
Username: 101
Server Domain: pbx.example.com → "to": "sip:101@pbx.example.com"- Different host: the app says
pbx.example.combut the dialplan sends the internal IP (sip:101@10.0.0.5). Send the domain the app uses. - Bare extension:
"to": "101"is rejected; it must be a fullsip:user@host. - Case: the user part is case-sensitive; the host isn't.
- Not enrolled yet: open the app once after setting up the account and check Settings → Incoming Calls shows it's registered with the relay.
401 invalid_api_key
The pk_ key is missing, mistyped, or was rotated. Re-copy it from Settings → Incoming Calls, and check the header is exactly Authorization: Bearer pk_…. If you rotated the key in the app, every PBX config that used the old one needs the new one.
402 subscription_required
The wake service needs an active subscription on the account (it's the one server we run; the app and your PBX do the rest for free). Subscribe or restore purchases in the app, then retry: no PBX changes needed.
422 invalid_payload
A field failed validation, and the response's issues array names it. Usual suspects: a malformed to, an over-length field, or broken JSON from unescaped quotes in a caller name. Keep payloads under 8 KB.
409 idempotency_conflict or previously_failed
Same call_id, different payload: retries must resend the identical body. previously_failed means that call already failed once; new call, new call_id.
502 apns_failed
The relay reached Apple but Apple couldn't deliver to any device. Usually transient; if it persists, the app may have been offloaded or reinstalled: open it once so it re-enrols a fresh push token.
The webhook works, but real calls don't ring
- No wake fired: check the webhook actually runs in your dialplan (watch the Asterisk CLI while calling; the
NoOpline from the guide should print). - Rings, then instantly stops: the INVITE went out before the app re-registered. Keep the
Wait(1.5)between webhook andDial. - Registration rejected: transport mismatch. The app defaults to TLS on 5061; if your PBX only speaks TCP or UDP, set the transport in the app under Settings → Advanced, or set up TLS properly.
It rings, but audio is one-way or missing
That's NAT, not the relay. On the endpoint make sure rtp_symmetric = yes, force_rport = yes, rewrite_contact = yes and direct_media = no, and that your firewall passes the RTP range (10000-20000/udp by default). If the PBX is behind NAT itself, set external_media_address on the transport.