SIPIS-less push calls¶
This article describes deployment requirements for SIPIS-less incoming push calls.
For deployments with SIPIS, refer to SIPIS documentation.
Quick Start¶
Use this checklist for first integration:
Configure SDK accounts with
sipisDisabledandpushNotificationsEnabled.Configure Push Token Reporter API.
Implement account-removal reporting so backend can remove stale push tuples after user log out.
Persist tuple data (
AppId,DeviceToken,Selector) for each registered device/account.On incoming call, load all tuples for the callee and send
NotifyIncomingCallto each tuple.Send SIP INVITE to all registered contacts.
Ensure pairing identifier
Idis present in SIP signaling viaX-Push-IDheader whenIdis not the SIP Call-ID.If call is canceled or answered elsewhere, send
NotifyIncomingCallMissedorNotifyIncomingCallAnsweredElsewhere.
Prerequisites and configuration¶
Enable the following preference keys:
sipisDisabledDisables SDK communication with SIPIS.
pushNotificationsEnabledEnables push notification integration.
Configure SDK SIP accounts to use the Push Token Reporter API.
Store the tuple reported by each device:
AppIdApp/platform/environment identifier.
DeviceTokenPush target identifier for the device.
SelectorSIP account selector on the device.
If one SIP account has multiple device registrations, persist all reported tuples.
Optional account XML property:
secondsToBeRegisteredOverrides how long the SDK tries to stay registered and wait for INVITE after incoming call push. Default is platform-specific in direct push flow (for example Android uses 5 seconds, iOS uses 3 seconds).
secondsToBeRegistered and Push Token Reporter configuration can both be provisioned via External provisioning API.
End-to-end sequence (backend + client)¶
Backend flow:
Collect and persist
AppId,DeviceToken,Selectortuples reported by the Push Token Reporter API.On incoming call, retrieve all tuples for the callee.
Build incoming-call push payload with pairing identifier
Id.Send incoming-call push to every tuple.
Send SIP INVITE to all registered contacts.
If a new contact REGISTERs while the call is pending, send INVITE to that contact, and continue sending INVITE to any additional contacts that REGISTER before the call is established.
If a contact re-REGISTERs and no provisional response was seen for that contact INVITE, send INVITE again.
Client flow:
App is in background or not running.
App receives VoIP push.
SDK starts and creates internal call representation.
App shows call UI / CallKit.
SDK starts SIP account registration and waits for SIP INVITE.
If SIP INVITE arrives, call continues as standard incoming call.
If SIP INVITE does not arrive, SDK terminates call after timeout (Android default: 5 seconds, iOS default: 3 seconds; can be overridden by
secondsToBeRegistered).
Handling user log out¶
When a user logs out or removes an account from the app, backend tuple data must be cleaned up. If stale tuples are kept, backend may continue sending intrusive call pushes to devices that no longer have the account configured. Repeated delivery failures or irrelevant pushes can also lead to pushes being blocked by the app.
Recommended approaches:
Use Account Removal Reporter to report account removal and remove the related tuple (
AppId,DeviceToken,Selector) on your backend.Or implement equivalent custom server ping logic in your app and remove the same tuple data on log out.
Account Removal Reporter is triggered on account log out/removal, but not on app uninstall or OS-level app data cleanup. Keep backend cleanup logic resilient to those cases as well.
Incoming call payload contract¶
Use verb = NotifyIncomingCall.
Field |
Required |
Source |
Notes |
|---|---|---|---|
|
Yes |
Backend logic |
Must be |
|
Yes |
Push Token Reporter |
Use |
|
Yes |
Push Token Reporter |
Device push token. |
|
Yes |
Push Token Reporter |
Account selector on device. |
|
Yes |
PBX / backend |
Use PBX call identifier when available; required for push-SIP pairing. |
|
No |
PBX / backend |
Caller display label shown in call UI (recommended). |
|
No |
PBX / backend |
Used with |
|
No |
PBX / backend |
Caller SIP domain (recommended). |
|
No |
Backend logic |
Use |
|
No |
Backend logic |
APNS-related; commonly |
|
No |
Backend logic |
Optional; include when required by your push template. Commonly |
|
Yes |
PBX / backend |
Unix timestamp in seconds. |
Missed/answered-elsewhere payload contract¶
Use:
verb = NotifyIncomingCallMissedfor missed call push.verb = NotifyIncomingCallAnsweredElsewherefor answered-elsewhere push.
Field |
Required |
Source |
Notes |
|---|---|---|---|
|
Yes |
Backend logic |
Must be one of the values above. |
|
Yes |
Push Token Reporter |
Use |
|
Yes |
Push Token Reporter |
Device push token. |
|
Yes |
Push Token Reporter |
Account selector on device. |
|
Yes |
PBX / backend |
Must match call identifier used for the incoming call push. |
|
No |
PBX / backend |
Caller display label (recommended). |
|
No |
PBX / backend |
Used with |
|
No |
PBX / backend |
Caller SIP domain (recommended). |
|
No |
Backend logic |
APNS-related; commonly |
|
No |
Backend logic |
Optional; include when required by your push template. Commonly |
|
Yes |
PBX / backend |
Unix timestamp in seconds. |
Pairing and cancellation logic¶
Push-SIP pairing prevents duplicate incoming calls in app UI.
Pairing requirements:
Incoming push must include
Id.If PBX Call-ID is known at push time, use that as
Id.If PBX Call-ID is not known at push time, use generated
Idand include that same value in SIP INVITE headerX-Push-ID.
The Id value is typically controlled by the PBX side. Even when the format is not under your control, presence and consistency are mandatory:
same
Idmust be used across related push events,and SIP signaling must carry matching identifier via
X-Push-IDfor pairing.
SDK can be notified about canceled incoming call by:
SIP CANCEL.
Missed/answered-elsewhere push.
SIP SIMPLE message with content type
application/x-acro-missed-calland headerX-Push-IDset to the related call identifier.
Validated cURL/Python examples¶
The following examples are production-safe templates with placeholders.
Incoming call push (cURL):
curl --header "Content-Type: application/json" \
--request POST \
--data '{
"DeviceToken": "<DEVICE_TOKEN>",
"Selector": "<SELECTOR>",
"AppId": "<PUSHAPPID_INCOMING_CALL>",
"verb": "NotifyIncomingCall",
"Id": "<CALL_PAIRING_ID>",
"UserDisplayName": "<CALLER_DISPLAY_NAME>",
"UserName": "<CALLER_USERNAME>",
"Domain": "<CALLER_DOMAIN>",
"Media": "audio",
"Timestamp": "<UNIX_TIMESTAMP_SECONDS>",
"Badge": "1",
"Sound": "default"
}' \
https://pnm.cloudsoftphone.com/pnm2/send
Incoming call push (Python):
#!/usr/bin/env python3
import requests
payload = {
"verb": "NotifyIncomingCall",
"DeviceToken": "<DEVICE_TOKEN>",
"AppId": "<PUSHAPPID_INCOMING_CALL>",
"Selector": "<SELECTOR>",
"UserDisplayName": "<CALLER_DISPLAY_NAME>",
"UserName": "<CALLER_USERNAME>",
"Domain": "<CALLER_DOMAIN>",
"Id": "<CALL_PAIRING_ID>",
"Media": "audio",
"Timestamp": "<UNIX_TIMESTAMP_SECONDS>",
"Badge": "1",
"Sound": "default"
}
response = requests.post("https://pnm.cloudsoftphone.com/pnm2/send", json=payload, timeout=10)
print(response.text)