Skip to content

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:

  1. Configure SDK accounts with sipisDisabled and pushNotificationsEnabled.
  2. Configure Push Token Reporter API.
  3. Implement account-removal reporting so backend can remove stale push tuples after user log out.
  4. Persist tuple data (AppId, DeviceToken, Selector) for each registered device/account.
  5. On incoming call, load all tuples for the callee and send NotifyIncomingCall to each tuple.
  6. Send SIP INVITE to all registered contacts.
  7. Ensure pairing identifier Id is present in SIP signaling via X-Push-ID header when Id is not the SIP Call-ID.
  8. If call is canceled or answered elsewhere, send NotifyIncomingCallMissed or NotifyIncomingCallAnsweredElsewhere.

Prerequisites and configuration

Preference keys

Enable the following preference keys:

Key Purpose
sipisDisabled Disables SDK communication with SIPIS.
pushNotificationsEnabled Enables push notification integration.

Configure SDK SIP accounts to use the Push Token Reporter API.

Reported device tuple

Store the tuple reported by each device:

Field Meaning
AppId App, platform, or environment identifier.
DeviceToken Push target identifier for the device.
Selector SIP account selector on the device.

If one SIP account has multiple device registrations, persist all reported tuples.

Optional account XML property

Property Meaning
secondsToBeRegistered Overrides how long the SDK tries to stay registered and wait for SIP INVITE after an incoming-call push. The default is platform-specific in direct-push flow: Android uses 5 seconds and 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:

  1. Collect and persist AppId, DeviceToken, Selector tuples reported by the Push Token Reporter API.
  2. On incoming call, retrieve all tuples for the callee.
  3. Build incoming-call push payload with pairing identifier Id.
  4. Send incoming-call push to every tuple.
  5. Send SIP INVITE to all registered contacts.
  6. 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.
  7. If a contact re-REGISTERs and no provisional response was seen for that contact INVITE, send INVITE again.

Client flow:

  1. App is in background or not running.
  2. App receives VoIP push.
  3. SDK starts and creates internal call representation.
  4. App shows call UI / CallKit.
  5. SDK starts SIP account registration and waits for SIP INVITE.
  6. If SIP INVITE arrives, call continues as standard incoming call.
  7. 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:

  1. Use Account Removal Reporter to report account removal and remove the related tuple (AppId, DeviceToken, Selector) on your backend.
  2. 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
verb Yes Backend logic Must be NotifyIncomingCall.
AppId Yes Push Token Reporter Use pushappid_incoming_call.
DeviceToken Yes Push Token Reporter Device push token.
Selector Yes Push Token Reporter Account selector on device.
Id Yes PBX / backend Use PBX call identifier when available; required for push-SIP pairing.
UserDisplayName No PBX / backend Caller display label shown in call UI (recommended).
UserName No PBX / backend Used with Domain to compose caller URI (recommended).
Domain No PBX / backend Caller SIP domain (recommended).
Media No Backend logic Use audio for audio-only calls.
Badge No Backend logic APNS-related; commonly 0 for incoming call push.
Sound No Backend logic Optional; include when required by your push template. Commonly default.
Timestamp Yes PBX / backend Unix timestamp in seconds.

Missed/answered-elsewhere payload contract

Use:

  • verb = NotifyIncomingCallMissed for missed call push.
  • verb = NotifyIncomingCallAnsweredElsewhere for answered-elsewhere push.
Field Required Source Notes
verb Yes Backend logic Must be one of the values above.
AppId Yes Push Token Reporter Use pushappid_other.
DeviceToken Yes Push Token Reporter Device push token.
Selector Yes Push Token Reporter Account selector on device.
Id Yes PBX / backend Must match call identifier used for the incoming call push.
UserDisplayName No PBX / backend Caller display label (recommended).
UserName No PBX / backend Used with Domain to compose caller URI (recommended).
Domain No PBX / backend Caller SIP domain (recommended).
Badge No Backend logic APNS-related; commonly 1 for missed calls.
Sound No Backend logic Optional; include when required by your push template. Commonly default.
Timestamp Yes PBX / backend Unix timestamp in seconds.

Pairing and cancellation logic

Push-SIP pairing prevents duplicate incoming calls in app UI.

Pairing requirements:

  1. Incoming push must include Id.
  2. If PBX Call-ID is known at push time, use that as Id.
  3. If PBX Call-ID is not known at push time, use generated Id and include that same value in SIP INVITE header X-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 Id must be used across related push events,
  • and SIP signaling must carry matching identifier via X-Push-ID for pairing.

SDK can be notified about canceled incoming call by:

  1. SIP CANCEL.
  2. Missed/answered-elsewhere push.
  3. SIP SIMPLE message with content type application/x-acro-missed-call and header X-Push-ID set 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)