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

Enable the following preference keys:

sipisDisabled

Disables SDK communication with SIPIS.

pushNotificationsEnabled

Enables push notification integration.

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

Store the tuple reported by each device:

AppId

App/platform/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:

secondsToBeRegistered

Overrides 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:

  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.

Incoming call payload

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.

Missed / answered-elsewhere payload

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)