Skip to main content

Inbox API

Sits on top of Conversations and powers the human-agent surface — who is currently viewing what, internal notes, saved filtered views, conversation routing, and quick-reply macros. Base path: /api/v1/inbox Authentication: API key (X-API-Key) or session JWT. The dashboard uses a Clerk session, and server-to-server callers can use an API key against the same endpoints.

Using the SDKs

Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Returns the typed ApiResponse envelope. See the SDK index at SDK quickstart.

Live presence

Used by the inbox UI to show “X is viewing” + typing indicators. Heartbeat the viewing endpoint roughly every 20 seconds while the conversation is open. The server holds presence for a 30-second TTL, so a 20-second cadence keeps it alive with margin — heartbeating at the full 30 seconds races the TTL and intermittently drops your own presence.

Example — heartbeat a conversation every 20 seconds

1. Register as viewing (send on open, then repeat every ~20 s):
ttl_seconds: 30 is the caveat from above, verbatim: refresh well inside 30 seconds — the dashboard heartbeats at 20 seconds so a slow call still lands before the TTL expires. session_id is optional; pass it when a user can have several tabs open so each tab registers its own presence row. 2. Read the current viewers:
3. Signal typing (send when the composer has focus; the server also auto-stops typing 5 seconds after your last call):
When the agent navigates away, DELETE /{conversationId}/viewing unregisters immediately rather than waiting out the 30-second TTL.

Internal notes

Team-only notes attached to a conversation. Never visible to the contact; surfaced inline with messages in the inbox UI.

Example — post a note with a mention

mentions carries the user ids your typeahead resolved while composing; each mentioned user gets a Notification Center entry. Response (201):

Saved views

Personal or team-wide filtered views over the conversation list — “My open WhatsApp conversations”, “VIP escalations”, “Stale > 4h”, etc.

Example — create a team view with filters

The filters object is the shared inbox filter AST — channels, statuses, assignee, tags, unread, search, date ranges, and more; every field is optional and combines conjunctively. scope: "team" requires owner/admin; "personal" (default) is visible only to you. Response (201):

Routing rules

Auto-assign incoming conversations to agents or teams based on channel, contact, content, or time. Rules are evaluated in priority order; first match wins.

Example — create a rule, then dry-run it

Create (owner/admin only — routing writes are team-wide):
The conditions + action shape is strict (unknown fields are rejected with VALIDATION_ERROR). keyword entries are plain substrings, or /regex/ patterns — regexes that risk ReDoS are rejected at save time. time_of_day narrows the match to a weekly window (here: weekdays 09:00–18:00); omit it to match around the clock. Action types: assign_user, assign_team, assign_round_robin, assign_skill_based, set_tag, set_priority, trigger_agent. Response (201):
Dry-run against a sample conversation — nothing is persisted or assigned:
Send rule (an inline create-style body) instead of rule_id to preview a rule before saving it. When matched is false, action comes back null — so a false verdict reads as { "matched": false, "action": null }.

Macros

Saved quick replies with optional variables, attachments, and post-actions (close, tag, assign).

Example — create a macro, then run it

Create with a mustache variable and a follow-up step:
Response (201):
Run it against a conversation, supplying the {{extra.*}} variables:
Built-in variables like {{contact.first_name}} resolve from the conversation’s contact; anything you pass in variables is exposed to the template as {{extra.<key>}}. On a partial failure the run returns HTTP 207 and failed_step reports the 1-based index of the step that threw.

See also