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 aconsole.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 arrayDeleting 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")Updated 15 days ago
