> ## 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.

# Utilities

> Conversations, contacts, calls, and phone settings

## Conversations

```ts theme={null}
import { buildKapsoFields } from '@kapso/whatsapp-cloud-api';

// List
const conversations = await client.conversations.list({
  phoneNumberId: '123',
  status: 'active',
  lastActiveSince: '2025-01-01T00:00:00Z',
  limit: 20,
  fields: buildKapsoFields(['contact_name'])
});

// Get one (includes phoneNumberId when using Kapso proxy)
const conv = await client.conversations.get({ conversationId: 'conv-123' });

// Update status
await client.conversations.updateStatus({ conversationId: 'conv-123', status: 'ended' });
```

## Contacts

```ts theme={null}
// List (Kapso proxy)
const contacts = await client.contacts.list({
  phoneNumberId: '123',
  customerId: '00000000-0000-0000-0000-000000000000',
  limit: 50,
  fields: buildKapsoFields(['contact_name'])
});

// Get one
const contact = await client.contacts.get({ phoneNumberId: '123', waId: '56911112222' });

// Update
await client.contacts.update({
  phoneNumberId: '123',
  waId: '56911112222',
  profileName: 'Alice',
  metadata: { tags: ['vip'] }
});
```

## Calls (Calling API)

```ts theme={null}
// Initiate (business-initiated)
await client.calls.connect({
  phoneNumberId: '123',
  to: '14085551234',
  session: { sdpType: 'offer', sdp: 'v=0...' },
  bizOpaqueCallbackData: 'tracking'
});

// Pre-accept / Accept / Reject / Terminate
await client.calls.preAccept({ phoneNumberId: '123', callId: 'wacid...', session: { sdpType: 'answer', sdp: 'v=0' } });
await client.calls.accept({ phoneNumberId: '123', callId: 'wacid...', session: { sdpType: 'answer', sdp: 'v=0' } });
await client.calls.reject({ phoneNumberId: '123', callId: 'wacid...' });
await client.calls.terminate({ phoneNumberId: '123', callId: 'wacid...' });

// Permission check
const perm = await client.calls.permissions.get({ phoneNumberId: '123', userWaId: '15551234567' });

// Kapso call logs
const callPage = await client.calls.list({
  phoneNumberId: '123',
  direction: 'INBOUND',
  limit: 20,
  fields: buildKapsoFields()
});
```

## Phone number settings & profile

```ts theme={null}
// Settings
const settings = await client.phoneNumbers.settings.get({ phoneNumberId: '123' });
await client.phoneNumbers.settings.update({ phoneNumberId: '123', fallbackLanguage: 'en_US' });

// Business profile
const profile = await client.phoneNumbers.businessProfile.get({ phoneNumberId: '123' });
await client.phoneNumbers.businessProfile.update({ phoneNumberId: '123', about: 'My business' });
```

## Kapso field helpers

```ts theme={null}
import {
  KAPSO_MESSAGE_FIELDS,
  buildKapsoFields,
  buildKapsoMessageFields
} from '@kapso/whatsapp-cloud-api';

// Request every Kapso message extra (same as fields: 'kapso(default)')
const selector = buildKapsoFields();

// Opt into a subset
const lightweight = buildKapsoMessageFields('flow_response', 'flow_token');

const history = await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: lightweight
});

// Backend also accepts the raw strings 'kapso(default)' or 'kapso(*)'
```

## Webhooks

```ts theme={null}
import express from 'express';
import { normalizeWebhook, verifySignature } from '@kapso/whatsapp-cloud-api/server';

const app = express();
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifySignature({
    appSecret: process.env.META_APP_SECRET!,
    rawBody: req.body,
    signatureHeader: req.headers['x-hub-signature-256'] as string
  })) {
    return res.status(401).end();
  }

  const payload = JSON.parse(req.body.toString('utf8'));
  const events = normalizeWebhook(payload);

  events.messages.forEach((message) => {
    console.log(message.type, message.kapso?.direction);
  });

  events.raw.accountAlerts?.forEach((alert) => {
    console.log('Account alert', alert.alertInfo?.alertType);
  });

  res.sendStatus(200);
});
```

`normalizeWebhook()` unwraps Meta’s Graph payload, converts it to the same structure returned by `messages.query`, and sets `kapso.direction` (`"inbound"`/`"outbound"`). SMB echoes are tagged with `kapso.source = "smb_message_echo"`, and every other webhook field (for example `accountAlerts`, `templateCategoryUpdate`) is available under `events.raw.<fieldName>`.

> See the full list of Kapso fields in [Kapso Extensions](/docs/whatsapp/typescript-sdk/kapso-extensions).

<Note>
  `verifySignature` depends on Node’s `crypto` module and is intended for server runtimes. If your bundler shows a warning about `node:crypto` being external, that’s expected — mark it as external or set the bundler platform to `node`.
</Note>
