Quick Start

Initialize the SDK once at the top of your app.

Tip: call init() in response to a user action (login click, an "enable calls" button) rather than on page load. init() requests microphone, location and notification permissions, and browsers treat permission prompts triggered by a user gesture much more favorably — prompts fired on page load may be auto-dismissed or silently blocked.

import { KasookooClient } from "kasookoo-sdk"

const kasookoo = await KasookooClient.init({
    publishableKey: "pk_live_...",     // from your Kasookoo dashboard
    subject: "[email protected]",       // the end user's EMAIL — see below
})

subject must be the end user's email address. The SDK uses it to resolve who that user is within your organization, so it can register this browser against them and route their calls and messages here. It must match an existing user's email — init() throws if it doesn't.

Already running your own Firebase project in this app? Push notifications need a small extra setup step so the SDK's service worker doesn't collide with yours — see Installation → Push notifications with your own Firebase project for the full walkthrough before you go further.

Correlation & tracing: The SDK automatically sends lifecycle correlation headers on API calls and optionally exports OpenTelemetry traces. See Error Handling & Tracing.

Quickstart: end to end

Initialize, listen for the events you care about, then place a call. This is the shortest path from an installed package to a working call — every piece here is covered in more depth on its own page.

import { KasookooClient } from "kasookoo-sdk"

// 1. Initialize — do this once, in response to a user gesture (e.g. a login button).
const kasookoo = await KasookooClient.init({
    publishableKey: "pk_live_...",
    subject: "[email protected]",   // the signed-in end user's email
})

// 2. Listen for the things that can happen to you passively.
kasookoo.on("call:incoming", (call) => {
    console.log(`${call.remote.name} is calling`)   // the SDK shows its own call window automatically
})
kasookoo.on("notification:message", (data) => {
    console.log("push payload:", data)               // see "Receiving messages" on the Messaging page to parse this
})
kasookoo.on("error", (err) => console.warn(err.code, err.message))

// 3. Do something — e.g. place a call.
const call = await kasookoo.initCall({
    roomName: `call_${crypto.randomUUID()}`,
    caller: { name: "Jane", email: "[email protected]", type: "agent" },
    callee: { name: "John", email: "[email protected]", type: "customer" },
})

call.on("state", (state) => console.log("call state:", state))
// The SDK's own call window (bottom-right, draggable) handles the rest —
// answer/reject, mute, hang up. Nothing else is required to get a working call.

Events

kasookoo.on("session:created", (info) => console.log(info.sessionId, info.allowedScopes))
kasookoo.on("session:refreshed", (info) => console.log("valid until", new Date(info.expiresAt)))
kasookoo.on("session:expired", ({ reason }) => { /* re-init or show a reconnect UI */ })
kasookoo.on("notification:message", (data) => { /* raw push data payload */ })
kasookoo.on("trace:request", ({ url, method, requestId, callTraceId, status, ok }) => { /* one per SDK HTTP request — see Error Handling & Tracing */ })
kasookoo.on("error", (err) => console.warn(err.code, err.message))

on() returns an unsubscribe function — call it to stop listening:

const off = kasookoo.on("notification:message", (data) => console.log(data))

// later, e.g. when a component unmounts or you no longer care:
off()

This is the only way to remove a listener added inline (an arrow function has no reference you could otherwise pass to off()). It matters most in frameworks with a component lifecycle — call off() on unmount, or the listener keeps firing (and keeps its closure alive) for as long as the SDK instance lives, even after the UI that cared about it is gone:

useEffect(() => {
    const off = kasookoo.on("call:incoming", (call) => setIncoming(call))
    return off   // React calls this automatically when the component unmounts
}, [kasookoo])

Calling the same off more than once is harmless — the second call is a no-op. You can also remove a listener with kasookoo.off(event, handler) directly, but that requires holding a reference to the original function, which the returned off() avoids needing.

Capabilities

Your publishable key is provisioned with a set of capabilities, returned as allowed_scopes when the session is created. Each feature is gated by its capability — if the session wasn't granted a feature's scope, calling that feature's method throws:

// session without the "cdr" capability:
await kasookoo.downloadCdr()
// → KasookooError { code: "Error",
//   message: "'property downloadCdr' does not exist on type KasookooClient " }
CapabilityGated methods
in_app_callinginitCall (and incoming calls / call:incoming)
sip_callinginitSipCall
in_app_messagingsendMessage, sendLocation, sendWhatsAppMessage, getConversations, getMessages, getUnreadCount, markRead, deleteConversation, deleteMessage
cdrgetCdr, downloadCdr
usercreateUser, updateUser, deleteUser, getUser, getUsers
associated_numbercreateAssociatedNumber, updateAssociatedNumber, deleteAssociatedNumber, getAssociatedNumbers

session, getScopes, on/off, and close are always available. authentication_calling:* scopes are not web-SDK features and are ignored.


Did this page help you?