SiteCallDevelopers

React Native SDK

Native calls on iOS and Android.

@sitecall/react-native owns the whole call on a phone: the ring push, the system call UI (CallKit on iOS, a self-managed ConnectionService on Android), SIP login and media, and the answer, decline and hang-up requests. Your JavaScript renders from one state stream.

Today the engine ships inside the Atriam and SiteCall apps and is not published to npm; product names one of those apps. Any native app can integrate with the same device contract below; ask SiteCall to enable the SDK for your bundle ids.

The engine

App.tsx

import { getEngine } from "@sitecall/react-native";

const engine = getEngine();
const { deviceId } = await engine.configure({ baseUrl: "https://sitecall.ai", product });

// On every login change (null on sign-out):
await engine.setSession({ authToken, workspaceId });

const off = engine.subscribe((calls) => render(calls)); // CallSnapshot[]

await engine.answer(callId);
await engine.startOutbound({ callId: crypto.randomUUID(), toNumber: "+15125550123", fromNumberId });
await engine.setHeld(callId, true);
await engine.hangup(callId);

// Sign-out: no push rings this phone again until the next session.
await engine.signOut();

End-user tokens on the phone

The engine's /v1 calls (emergency location, and your own) use an end-user token, never your application key. For your users, set a provider that asks your backend, which mints the token with POST /api/v1/sessions:

engine.setApiTokenProvider(async () => {
  const { token, workspaceId } = await fetch("https://api.example.com/sitecall-token", {
    headers: { authorization: `Bearer ${myLoginToken}` },
  }).then((r) => r.json());
  return { token, workspaceId };
});

The device contract

Whatever renders the call, a phone becomes a ringing endpoint of one of your users in three steps, all with that user's end-user token (scope devices:*):

  1. POST /api/v1/devices with the install id, the platform, its push tokens and your bundleId. iOS rings through its VoIP (PushKit) token, with the APNs alert token for other pushes; Android rings through its FCM token. SiteCall sends those pushes with your application's own APNs and FCM credentials. Register again whenever a token changes: it is also the heartbeat.
  2. POST /api/v1/credentials { deviceId } for the SIP credential the phone logs in with. It lasts 30 minutes and is reused while more than 5 remain, so ask again before each login.
  3. On sign-out, DELETE /api/v1/devices/{deviceId}: the phone stops ringing and its credential is revoked.

with @sitecall/cli, as the user

await asUser.devices.register({
  deviceId,
  platform: "ios",
  voipToken,
  pushToken,
  bundleId: "com.example.field",
  appVersion: "4.2.0",
});
const credential = await asUser.credentials.create({ deviceId });
// credential.sipUsername, credential.sipPassword, credential.expiresAt

A ring push carries a narrow answer token for that one call and device, valid for 2 minutes and used once; it lets a phone woken from a killed state answer and mint a fresh credential before its first request. Rings for each workspace show that workspace's name, and a user in several workspaces is rung only for the workspace the call is for.