Messaging

Two channels are supported: normal in-app messages and WhatsApp. In both cases the first message sent to a room also establishes the conversation — there is no separate setup call. Reuse the same roomName to keep messages in the same conversation thread.

Normal messages

await kasookoo.sendMessage({
    senderUserId: "user_123",
    receiverUserId: "user_456",
    roomName: "chat_user123_user456",
    message: "Hello!",
    contentType: "text",              // optional — defaults to "text"
    metadata: { orderId: "ord_42" },  // optional — arbitrary extra data attached to the message
})

Sharing location

sendLocation shares the user's current position as a normal in-app message — same channel and same in_app_messaging capability as sendMessage, there is no separate location capability. You don't provide coordinates yourself; the SDK reads them from the browser at send time:

await kasookoo.sendLocation({
    senderUserId: "user_123",
    receiverUserId: "user_456",
    roomName: "chat_user123_user456",
    metadata: { note: "meet here" },  // optional
})

Permission. init() requests location permission once, best-effort — a denial there never fails init(), it just means this method will throw when you actually call it:

try {
    await kasookoo.sendLocation({ senderUserId: "user_123", receiverUserId: "user_456", roomName: "chat_user123_user456" })
} catch (err) {
    if (err instanceof KasookooError && err.code === "location_permission_denied") {
        // show your own "enable location" prompt
    }
}

Other codes: location_unavailable (position could not be determined) and location_unsupported (geolocation isn't available in this environment).

WhatsApp messages

WhatsApp sends additionally need the associatedNumberId — the organization number the message goes out from:

await kasookoo.sendWhatsAppMessage({
    senderUserId: "user_123",
    receiverUserId: "user_456",
    roomName: "whatsapp_chat_user123",
    message: "Hello via WhatsApp!",
    associatedNumberId: "num_abc123",
    contentType: "text",              // optional — defaults to "text"
})

A "WHATSAPP" associated number is a prerequisite for this. associatedNumberId is the id of one, and there's no default — create it first with createAssociatedNumber(). See Associated Numbers.

Receiving messages

Incoming messages arrive as push payloads on the notification:message event (see Quick Start → Events) — dedicated typed message events are on the roadmap. The payload is Record<string, string> — every value is a string, including anything numeric — and carries the same underlying fields as a ChatMessage from getMessages(), so the two can usually share one mapping function:

function toChatMessage(data: Record<string, string>) {
    // Call-signaling pushes land on the same event — skip anything that
    // isn't a chat message before treating it as one.
    if (!data.room_name || !data.message) return null

    return {
        id: data.id,
        conversationId: data.conversation_id,
        senderUserId: data.sender_user_id,
        receiverUserId: data.receiver_user_id,
        roomName: data.room_name,
        message: data.message,
        channel: data.channel,           // "normal" | "whatsapp"
        messageType: data.message_type,  // e.g. "text"
        createdAt: data.created_at,
    }
}

kasookoo.on("notification:message", (data) => {
    const message = toChatMessage(data)
    if (!message) return   // a call-signaling push, not a chat message
    appendToThread(message)
})

Push payloads are server-controlled and untyped by design (Record<string, string>) — confirm the exact field set with a console.log(data) in your own environment before relying on it, since it can gain fields over time.

Conversations and message history

Read-only — the SDK does not cache or persist results; call these again whenever you need fresh data.

const { items: conversations, pagination } = await kasookoo.getConversations({ skip: 0, limit: 50 })
// all fields optional — `userId` defaults to the session's subject (your end user); override only to fetch someone else's

const { items: messages } = await kasookoo.getMessages(conversations[0].conversation_id, { skip: 0, limit: 50 })
// same defaulting as getConversations — `userId` defaults to the session's subject; override only to fetch someone else's

const { unread_count } = await kasookoo.getUnreadCount()
const { unread_count: forOneThread } = await kasookoo.getUnreadCount({ conversationId: conversations[0].conversation_id })

Both getConversations() and getMessages() return { items, pagination: { total, skip, limit } }. A Conversation's channel is "normal" or "whatsapp"; a ChatMessage's channel is the same, and its message_type describes the content (e.g. "text").

Marking a conversation read

await kasookoo.markRead({ conversationId: "conv_...", messageIds: ["id1"] })  // marks all the messages whose messageId is in  messageIds array

Deleting a conversation

Deletes a conversation and its messages — there is no option to keep the messages while removing just the conversation:

const { conversation_id, delete_messages } = await kasookoo.deleteConversation("conv_...")
// `userId` defaults to the session's subject; pass a second argument to override
await kasookoo.deleteConversation("conv_...", "user_456")

Deleting a message

const { message_id } = await kasookoo.deleteMessage("msg_...")
// `userId` defaults to the session's subject; pass a second argument to override
await kasookoo.deleteMessage("msg_...", "user_456")

Did this page help you?