@sippet-ai/sdk-js
v0.0.18
Published
Sippet AI's SDK to enable telephony calling features in any web application.
Readme
Sippet AI JS SDK
Typed JavaScript/TypeScript SDK for Sippet AI.
This package uses strict entrypoints:
@sippet-ai/sdk-js/clientfor browser-safe realtime, call control, and PCM media helpers.@sippet-ai/sdk-js/serverfor RPC actions and server helpers.
Install
npm install @sippet-ai/sdk-jsEntry points
@sippet-ai/sdk-js/client- Realtime:
initSocket,joinEventsChannel,createRealtimeEventsClient - Call control:
startOutboundCallWithMedia,answerQueuedCallWithMedia,joinLiveCallMedia,leaveCall,endCall - PCM media:
connectCallMedia,setInputDevice,setOutputDevice,setConferenceMuted,setCallHold - Deprecated SIP compatibility shims:
connectSipSession,placeSipCall,hangupSipCall,disconnectSipSession
- Realtime:
@sippet-ai/sdk-js/server- RPC functions
createServerClientto inject API key headers into RPC calls
@sippet-ai/sdk-js/realtime- Realtime-only helper entrypoint
Server usage (@sippet-ai/sdk-js/server)
Use this entrypoint in your backend only.
Create an RPC client
import { createServerClient } from "@sippet-ai/sdk-js/server";
const sippet = createServerClient({
apiKey: process.env.SIPPET_SECRET_API_KEY!,
});
const calls = await sippet.listCalls({
fields: ["id", "callUuid", "status", "startedAt"],
page: { limit: 50, offset: 0, count: true },
});Mint a realtime session token
import { mintRealtimeSessionToken } from "@sippet-ai/sdk-js/server";
const token = await mintRealtimeSessionToken({
secretApiKey: process.env.SIPPET_SECRET_API_KEY!,
baseUrl: "https://api.sippet.ai",
});
// token = {
// token,
// tokenType: "realtime_session",
// scope: "events",
// expiresAt,
// ttlSeconds
// }Call the RPC action directly (issueOperatorAccessToken)
import { createServerClient } from "@sippet-ai/sdk-js/server";
const sippet = createServerClient({
apiKey: process.env.SIPPET_SECRET_API_KEY!,
});
const result = await sippet.issueOperatorAccessToken({
input: { operatorEmail: "[email protected]" },
});
if (!result.success) {
throw new Error(result.errors.map((e) => e.message).join(", "));
}
console.log(result.data.token);Client usage (@sippet-ai/sdk-js/client)
Use this entrypoint in browser apps.
Initialize a shared client (recommended)
import { initClient } from "@sippet-ai/sdk-js/client";
const sippet = initClient({
baseUrl: "https://api.sippet.ai",
headers: {
Authorization: `Bearer ${operatorAccessToken}`,
},
});
const me = await sippet.whoAmI({
fields: ["id", "email", "fullName"],
});Use this same sippet instance everywhere in your app (and pass it to the
operator widget) to keep one SDK state/config source.
In modules where you don't initialize directly, use getClient():
import { getClient } from "@sippet-ai/sdk-js/client";
const sippet = getClient();Realtime events with auto-refresh
import { initClient } from "@sippet-ai/sdk-js/client";
const sippet = initClient({
baseUrl: "https://api.sippet.ai",
});
const realtime = sippet.createRealtimeEventsClient({
getRealtimeToken: async () => {
// This is to your backend server to securely mint a realtime token
const response = await fetch("/api/sippet/realtime-token", {
method: "POST",
});
if (!response.ok) {
throw new Error("Failed to fetch realtime token from backend");
}
return response.json();
},
refreshSkewMs: 60_000,
});
realtime.on("incoming_call", (payload) => {
console.log("incoming_call", payload);
});
realtime.on("call_answered", (payload) => {
console.log("call_answered", payload);
});
await realtime.start();
// later
// realtime.stop();Channel events names:
incoming_callcall_answeredcall_endedoperator_status_changecall_queue_entry_updatedcall_queue_entry_deletedcall_participant_joinedcall_participant_leftcall_transcript_deltacall_transcript_completedcall_ai_audit_eventcall_ai_usage
Call control helpers
For browser call control, use the high-level helpers. These use Sippet's operator media websocket and raw PCM16 audio.
import { initClient } from "@sippet-ai/sdk-js/client";
const sippet = initClient({
baseUrl: "https://api.sippet.ai",
headers: {
Authorization: `Bearer ${operatorAccessToken}`,
},
});
const outbound = await sippet.startOutboundCallWithMedia({
input: {
phoneNumber: "+15551234567",
aiAgentId: "AI_AGENT_ID",
},
inputMuted: false,
});
if (!outbound.success) {
throw new Error(outbound.errors.map((error) => error.message).join(", "));
}
// `media` contains the operator-media websocket URL and PCM config.
console.log(outbound.data.callUuid, outbound.data.media.audio);
await sippet.leaveCall({
input: { callUuid: outbound.data.callUuid, reason: "left_call" },
});
await sippet.endCall({
input: { callUuid: outbound.data.callUuid },
});These helpers orchestrate RPC + media lifecycle for common operator flows.
Receive and join live calls
Use realtime events to learn about incoming calls, then answer the queue entry and connect PCM media in one call.
const realtime = sippet.createRealtimeEventsClient({
getRealtimeToken: async () => {
const response = await fetch("/api/sippet/realtime-token", {
method: "POST",
});
return response.json();
},
});
realtime.on("call_queue_entry_updated", async (payload) => {
const queueEntry = payload as { id?: string; state?: string };
if (!queueEntry.id || queueEntry.state !== "waiting") return;
const answer = await sippet.answerQueuedCallWithMedia({
queueEntryId: queueEntry.id,
inputMuted: false,
});
if (!answer.success) {
console.error(answer.errors);
}
});
await realtime.start();If your app already has a callUuid, use joinLiveCallMedia:
const joined = await sippet.joinLiveCallMedia({
input: { callUuid: "CALL_UUID" },
inputMuted: false,
});Deprecated SIP compatibility
The previous SIP method names are still exported for backwards compatibility. They log a browser console warning and route to the PCM operator-media lifecycle where possible. New integrations should use the PCM helpers above.
await sippet.connectSipSession({
server: "wss://YOUR_OLD_SIP_DOMAIN:7443",
domain: "YOUR_OLD_SIP_DOMAIN",
username: "OLD_SIP_USERNAME",
password: "OLD_SIP_PASSWORD",
});
await sippet.placeSipCall({
roomId: "CALL_UUID",
});
await sippet.hangupSipCall();
await sippet.disconnectSipSession();connectSipSession is now a deprecated no-op. placeSipCall expects roomId
or callUuid and joins the Sippet operator-media websocket for that call.
hangupSipCall and disconnectSipSession disconnect local PCM media; use
leaveCall or endCall when you need server-side call control.
Security model
- Never expose Sippet secret API keys in browsers.
- Use
mintRealtimeSessionTokenon your backend to issue short-lived websocket tokens. - Use realtime
session_tokenfor websocket subscriptions only. - Run RPC/data access from your backend via
@sippet-ai/sdk-js/server.
