Skip to content

Contacts

Contacts represent WhatsApp users you communicate with. Each contact stores their phone number, profile information, and conversation history.

Retrieve a paginated list of contacts.

Terminal window
GET /api/contacts
Parameter Type Description
page integer Page number (default: 1)
limit integer Page size, 1–100. Default 50.
search string Search by profile name (case-insensitive) or phone number. Truncated at 1000 characters.
tags string Comma-separated tags; matches contacts having ANY of them

Contacts are ordered by last_message_at DESC (nulls last), then created_at DESC.

{
"status": "success",
"data": {
"contacts": [
{
"id": "uuid",
"phone_number": "1234567890",
"name": "John",
"profile_name": "John",
"avatar_url": "https://...",
"status": "active",
"tags": ["vip", "billing"],
"metadata": { "custom_field": "value" },
"last_message_at": "2024-01-01T12:00:00Z",
"last_message_preview": "See you tomorrow!",
"unread_count": 2,
"assigned_user_id": "uuid",
"whatsapp_account": "Main Business",
"last_inbound_at": "2024-01-01T11:00:00Z",
"service_window_open": true,
"marketing_opt_out": false,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
],
"total": 100,
"page": 1,
"limit": 50
}
}
Field Type Description
whatsapp_account string The name of the WhatsApp account the contact belongs to (not a UUID)
assigned_user_id uuid The agent the contact is assigned to, if any
unread_count integer Number of unread incoming messages
last_message_preview string Preview text of the most recent message
service_window_open boolean True if the customer messaged within the last 24 hours (last_inbound_at)
marketing_opt_out boolean Whether the contact has opted out of marketing messages
status string Always the literal "active" — contacts have no status column.
name string Mirrors profile_name; both hold the same value.

Retrieve a single contact by ID.

Terminal window
GET /api/contacts/{id}
{
"status": "success",
"data": {
"id": "uuid",
"phone_number": "1234567890",
"name": "John",
"profile_name": "John",
"avatar_url": "https://...",
"status": "active",
"tags": ["vip"],
"assigned_user_id": "uuid",
"whatsapp_account": "Main Business",
"metadata": {
"custom_field": "value"
},
"unread_count": 0,
"last_message_at": "2024-01-01T12:00:00Z",
"last_message_preview": "Thanks!",
"service_window_open": true,
"marketing_opt_out": false,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
}

Create a new contact (or restore a soft-deleted one with the same phone number). Requires contacts:write.

Terminal window
POST /api/contacts
{
"phone_number": "+1234567890",
"profile_name": "John Doe",
"whatsapp_account": "Main Business",
"tags": ["vip"],
"metadata": {
"custom_field": "value"
}
}
Field Type Required Description
phone_number string Yes Contact phone number (a leading + is stripped)
profile_name string No Display name for the contact
whatsapp_account string No Name of the WhatsApp account to associate (not a UUID)
tags string[] No Tags to attach to the contact
metadata object No Freeform custom data

Returns the created contact in the same shape as Get Contact.

Update an existing contact.

Terminal window
PUT /api/contacts/{id}

Only the fields you send are updated.

{
"profile_name": "John Smith",
"whatsapp_account": "Main Business",
"tags": ["vip", "billing"],
"metadata": {
"custom_field": "updated_value"
},
"assigned_user_id": "uuid",
"clear_assigned_agent": false
}
Field Type Description
profile_name string Display name
whatsapp_account string Name of the associated WhatsApp account
tags string[] Replaces the contact’s tags
metadata object Replaces the metadata object
assigned_user_id uuid Assign the contact to an agent
clear_assigned_agent boolean Set true to unassign the contact (takes precedence over assigned_user_id)

Returns the full updated contact (same shape as Get Contact).

Delete a contact and all associated data.

Terminal window
DELETE /api/contacts/{id}
{
"status": "success",
"data": null
}

Assign a contact to a team member.

Terminal window
PUT /api/contacts/{id}/assign
{
"user_id": "uuid"
}

To unassign a contact, set user_id to null:

{
"user_id": null
}
{
"status": "success",
"data": {
"message": "Contact assigned successfully",
"assigned_user_id": "uuid"
}
}

Replace the full set of tags on a contact. Requires contacts:write.

Terminal window
PUT /api/contacts/{id}/tags
{
"tags": ["vip", "billing"]
}
{
"status": "success",
"data": {
"message": "Contact tags updated",
"tags": ["vip", "billing"]
}
}

Mark all incoming messages from a contact as read (clears the unread badge). Used by the chat view when the conversation is open.

Terminal window
POST /api/contacts/{id}/mark-read
{
"status": "success",
"data": { "status": "ok" }
}

The metadata field is a freeform JSON object that can hold any structured data. It is displayed in the Contact Info panel alongside tags and session data.

Different value types are rendered differently in the panel:

Type Display
String, number Key-value row
Boolean Yes / No badge
Object Collapsible section with key-value rows
Array of objects Collapsible table with column headers
Array of primitives Inline badges
{
"metadata": {
"plan": "premium",
"age": 30,
"active": true,
"address": {
"city": "Mumbai",
"state": "Maharashtra",
"zip": "400001"
},
"orders": [
{ "id": "ORD-001", "amount": 1500, "status": "delivered" },
{ "id": "ORD-002", "amount": 2300, "status": "pending" }
],
"interests": ["fitness", "tech", "travel"]
}
}

This renders as:

  • General section — plan, age, and active as key-value rows (boolean shown as a badge)
  • Address section — collapsible key-value pairs for city, state, zip
  • Orders section — collapsible table with Id, Amount, Status columns
  • Interests section — inline badges: fitness, tech, travel

The panel supports one level of nesting. Top-level keys are organized as follows:

Top-level value Rendered as
Primitive (string, number, boolean) Row in the General section
Object Its own collapsible section with key-value rows
Array of objects Its own collapsible section with a table
Array of primitives Its own collapsible section with badges

Values inside a nested object or array are always displayed as flat text. If a nested object contains another object, the inner value is shown as a raw JSON string. For example:

{
"metadata": {
"address": {
"city": "Mumbai",
"location": { "lat": 19.07, "lng": 72.87 }
}
}
}

Here city displays as Mumbai, but location displays as {"lat":19.07,"lng":72.87}.

Retrieve chatbot session data for a contact, including collected variables and panel configuration.

Terminal window
GET /api/contacts/{id}/session-data
{
"status": "success",
"data": {
"session_id": "uuid",
"flow_id": "uuid",
"flow_name": "Customer Support Flow",
"session_data": {
"customer_name": "John Doe",
"customer_email": "john@example.com",
"order_id": "ORD-12345",
"order_status": "shipped"
},
"panel_config": {
"sections": [
{
"id": "customer",
"label": "Customer Info",
"columns": 1,
"collapsible": true,
"default_collapsed": false,
"order": 1,
"fields": [
{"key": "customer_name", "label": "Name", "order": 1},
{"key": "customer_email", "label": "Email", "order": 2}
]
},
{
"id": "order",
"label": "Order Details",
"columns": 2,
"collapsible": true,
"default_collapsed": true,
"order": 2,
"fields": [
{"key": "order_id", "label": "Order ID", "order": 1},
{"key": "order_status", "label": "Status", "order": 2}
]
}
]
}
}
}
Field Type Description
session_id uuid The chatbot session ID
flow_id uuid The flow that collected the data
flow_name string Name of the flow
session_data object Key-value pairs of collected variables
panel_config object Panel display configuration from the flow

Contacts are the scope for conversation messages and internal notes.

Messages are sent and retrieved under the contact resource. See the Messages API for full request/response details.

Method Path Description
GET /api/contacts/{id}/messages List messages for a contact (paginated)
POST /api/contacts/{id}/messages Send a message to the contact
POST /api/contacts/{id}/messages/{message_id}/reaction Add or remove an emoji reaction on a message

Internal, contact-scoped notes visible to agents (never sent to the customer). Requires chat:read to list and chat:write to modify.

Method Path Description
GET /api/contacts/{id}/notes List notes for a contact (cursor-paginated, oldest first)
POST /api/contacts/{id}/notes Create a note
PUT /api/contacts/{id}/notes/{note_id} Update a note
DELETE /api/contacts/{id}/notes/{note_id} Delete a note
{
"content": "Customer prefers email follow-up."
}
{
"status": "success",
"data": {
"id": "uuid",
"contact_id": "uuid",
"created_by_id": "uuid",
"created_by_name": "Admin User",
"content": "Customer prefers email follow-up.",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
}

The list endpoint returns { "notes": [...], "total": <n>, "has_more": <bool> }.