> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat SDK

> Build WhatsApp agents with Chat SDK and Kapso.

Use `@kapso/chat-adapter` when a [Chat SDK](https://chat-sdk.dev) agent needs to receive Kapso WhatsApp webhooks, reply in threads, send buttons or media, and read Kapso conversation history.

Use [`@kapso/whatsapp-cloud-api`](/docs/whatsapp/typescript-sdk/introduction) directly when you need raw templates, flows, catalogs, or lower-level WhatsApp API calls.

## Installation

```bash theme={null}
npm install chat @kapso/chat-adapter @chat-adapter/state-memory
```

Requires Node.js >= 20.19.

`@chat-adapter/state-memory` is good for local development. For production, use durable Chat SDK state.

## Quickstart

```ts theme={null}
import { Chat } from 'chat';
import { createMemoryState } from '@chat-adapter/state-memory';
import { createKapsoAdapter } from '@kapso/chat-adapter';

export const bot = new Chat({
  userName: 'support',
  state: createMemoryState(),
  adapters: {
    kapso: createKapsoAdapter(),
  },
});

bot.onDirectMessage(async (thread, message) => {
  await thread.post(`You said: ${message.text}`);
});
```

## Environment

```bash theme={null}
KAPSO_API_KEY=your_project_api_key
KAPSO_PHONE_NUMBER_ID=your_phone_number_id
KAPSO_WEBHOOK_SECRET=your_webhook_secret
```

| Variable                | Required    | Use                                                                              |
| ----------------------- | ----------- | -------------------------------------------------------------------------------- |
| `KAPSO_API_KEY`         | Yes         | Sends messages, reads history, contacts, conversations, and media through Kapso. |
| `KAPSO_PHONE_NUMBER_ID` | Recommended | Default WhatsApp phone number ID. Required for `openDM()`.                       |
| `KAPSO_WEBHOOK_SECRET`  | Recommended | Verifies Kapso `X-Webhook-Signature` deliveries.                                 |
| `KAPSO_BASE_URL`        | No          | Kapso proxy URL. Defaults to `https://api.kapso.ai/meta/whatsapp`.               |
| `KAPSO_BOT_USERNAME`    | No          | Bot display name. Defaults to the Chat SDK `userName`.                           |

You can also pass config directly:

```ts theme={null}
createKapsoAdapter({
  kapsoApiKey: process.env.KAPSO_API_KEY,
  phoneNumberId: process.env.KAPSO_PHONE_NUMBER_ID,
  webhookSecret: process.env.KAPSO_WEBHOOK_SECRET,
});
```

## Webhook route

Kapso sends platform webhooks as `POST` requests. Forward the raw `Request` to Chat SDK.

```ts theme={null}
import { bot } from '@/lib/bot';

export async function POST(request: Request): Promise<Response> {
  return bot.webhooks.kapso(request);
}
```

Configure the webhook in Kapso:

| Setting      | Value                                                                          |
| ------------ | ------------------------------------------------------------------------------ |
| Endpoint URL | Your public `POST` route, for example `https://app.example.com/webhooks/kapso` |
| Secret key   | Same value as `KAPSO_WEBHOOK_SECRET`                                           |
| Events       | `whatsapp.message.received`                                                    |

Add `whatsapp.message.sent` only if your app needs sent-message echoes.

## Send replies

Reply inside a direct message handler:

```ts theme={null}
bot.onDirectMessage(async (thread, message) => {
  await thread.post({
    markdown: `Received: **${message.text}**`,
  });
});
```

Start an outbound WhatsApp conversation:

```ts theme={null}
import type { KapsoAdapter } from '@kapso/chat-adapter';

const adapter = bot.getAdapter('kapso') as KapsoAdapter;
const threadId = await adapter.openDM('15551234567');
const thread = bot.thread(threadId);

await thread.post('Hello from Kapso.');
```

## Buttons

Chat SDK cards with buttons become WhatsApp reply buttons.

```tsx theme={null}
import { Actions, Button, Card } from 'chat';

await thread.post(
  Card({
    title: 'Approve refund?',
    children: [
      Actions([
        Button({ id: 'approve', label: 'Approve', value: 'refund-123' }),
        Button({ id: 'reject', label: 'Reject', value: 'refund-123' }),
      ]),
    ],
  }),
);
```

Handle button clicks:

```ts theme={null}
bot.onAction('approve', async (action) => {
  await action.thread?.post(`Approved ${action.value}`);
});
```

WhatsApp supports up to 3 reply buttons. Button labels must be 1-20 characters.

## Media

Send files through Chat SDK:

```ts theme={null}
await thread.post({
  markdown: 'Here is the receipt.',
  files: [
    {
      filename: 'receipt.pdf',
      mimeType: 'application/pdf',
      data: await fs.promises.readFile('receipt.pdf'),
    },
  ],
});
```

Inbound media appears as Chat SDK attachments. When Kapso includes a mirrored media URL, the attachment has `url`. When a WhatsApp media ID is available, the attachment has lazy `fetchData()`.

## History

With `KAPSO_API_KEY`, history reads from Kapso:

```ts theme={null}
const page = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
```

`fetchThread()` enriches metadata with Kapso contact and conversation records when available.

## Source

<Card title="GitHub repository" icon="github" href="https://github.com/gokapso/chat-sdk-adapter">
  Source code, examples, and issue tracker for `@kapso/chat-adapter`.
</Card>
