Skip to main content
Kapso returns Meta-compatible objects by default. Opt in to extra fields using fields=kapso(...) on list endpoints. Works with:
  • REST API: Add ?fields=kapso(...) query parameter
  • TypeScript SDK: Pass fields option with helper functions or string
These extensions add valuable context like message direction, media URLs, conversation details, and more.

Usage

TypeScript SDK

The SDK includes helper functions for common field sets:
import {
  buildKapsoFields,
  buildKapsoMessageFields
} from '@kapso/whatsapp-cloud-api';

// All default Kapso message fields
const page = await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: buildKapsoFields()
});

// Subset of fields
const subset = await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: buildKapsoMessageFields('flow_response', 'flow_token')
});

// Or use string format
const messages = await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: 'kapso(default)'
});

REST API

Add the fields query parameter:
# All default Kapso fields
GET /v24.0/{phone_number_id}/messages?fields=kapso(default)

# Specific fields only
GET /v24.0/{phone_number_id}/messages?fields=kapso(direction,media_url,contact_name)

# Omit Kapso fields (Meta-only)
GET /v24.0/{phone_number_id}/messages?fields=kapso()
Available selectors:
  • kapso(default) or kapso(*) or kapso(all) - All default Kapso fields
  • kapso(field1,field2,...) - Specific fields only
  • kapso() - Omit Kapso fields entirely

Message fields

FieldDescription
directionInbound or outbound based on the business number.
statusServer-side message status when available.
processing_statusInternal processing status when available.
phone_numberBusiness phone number for the message.
has_mediaTrue when a media blob is attached.
media_dataURL, filename, content type, and byte size for stored media.
media_urlDirect URL to the attached media. Inbound: immediate. Outbound: appears shortly after send.
whatsapp_conversation_idInternal conversation identifier.
contact_nameDisplay name when known.
message_type_dataPer-type hints such as caption, sticker info, or location values.
contentOriginal message fragment stored by Kapso (for example, entire interactive/catalog payloads).
flow_responseParsed Flows response JSON.
flow_tokenToken from a Flows response when present.
flow_nameName from a Flows response when present.
order_textOptional note from order messages.

Conversation fields

Use these with conversations endpoint.
FieldDescription
contact_nameDisplay name for the contact linked to the conversation.
messages_countTotal number of stored messages in the conversation.
last_message_idWAMID of the most recent message in the conversation.
last_message_typeType of the most recent message (for example text, image, reaction).
last_message_timestampISO 8601 timestamp of the most recent message.
last_message_textText or caption preview when available (may be empty for non-text types).
last_inbound_atISO 8601 timestamp of the most recent inbound message.
last_outbound_atISO 8601 timestamp of the most recent outbound message.

Examples

All Kapso fields

await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: buildKapsoFields()
});

Subset of fields

await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: 'kapso(flow_response,flow_token,media_url)'
});

Omit Kapso fields

await client.messages.query({
  phoneNumberId: '123',
  limit: 20,
  fields: 'kapso()'
});

Webhooks

The SDK includes a normalization helper for Meta webhooks. It returns the same structure as history queries and sets kapso.direction. SMB echoes are tagged with kapso.source = "smb_message_echo". Other webhook fields are available under events.raw.<fieldName>.
import { normalizeWebhook, verifySignature } from '@kapso/whatsapp-cloud-api/server';

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 events = normalizeWebhook(JSON.parse(req.body.toString('utf8')));
  events.messages.forEach(m => console.log(m.type, m.kapso?.direction));
  res.sendStatus(200);
});