Shared team inbox
Every WhatsApp conversation for the organization in one list, ordered by most recent activity.
The Inbox is where your team has day-to-day conversations with customers over WhatsApp. It's a shared, real-time view: incoming messages arrive live over WebSocket, agents reply with text, media, buttons, or approved templates, and each conversation carries its own assignment, tags, and private notes.
Shared team inbox
Every WhatsApp conversation for the organization in one list, ordered by most recent activity.
Assignment
Route a conversation to a specific agent so ownership is clear.
Tags
Colour-coded labels for filtering and triage (e.g. vip, billing, lead).
Private notes
Internal-only annotations on a conversation — never sent to the customer.
The left-hand list is the set of contacts the signed-in user is allowed to see, ordered by last_message_at (most recent first, contacts with no messages last). Each row surfaces:
| Field | Meaning |
|---|---|
| Profile name / phone | The contact's WhatsApp profile name, falling back to the phone number. Both can be masked org-wide. |
| Last message preview | A short preview of the most recent message ([Image], [Document: …], or truncated text). |
| Unread count | Number of incoming messages that haven't been marked read. |
| Assigned agent | The agent the conversation is routed to, if any. |
| Tags | The contact's tags. |
| Service window | Whether the 24-hour free-form messaging window is open (see below). |
The list supports server-side search and tag filtering:
?tags=vip,billing).These map to the search and tags query parameters on GET /api/contacts — see the Contacts API.
A conversation's unread count is the number of incoming messages whose status is not yet read. Opening the conversation and calling mark-as-read clears it (see Marking messages as read). When the chatbot auto-handles an exchange, it marks the incoming messages read for you so bot-handled chats don't leave a stale unread badge.
WhatsApp enforces a 24-hour customer service window. It opens each time the customer sends you a message and lasts 24 hours from that last inbound message. Whatomate tracks this per contact as service_window_open (true when the last inbound message was less than 24 hours ago).
What the window controls:
| Window state | What you can send |
|---|---|
| Open (customer messaged within 24h) | Free-form messages — text, media, interactive buttons, reactions. |
| Closed (no inbound in 24h) | Only pre-approved message templates. Free-form messages will be rejected by Meta. |
What a user sees in the inbox depends on their role's permissions:
chat:read — the user can open conversations. Combined with contacts:read, they see every conversation in the organization.contacts:read — visibility is narrowed to conversations the user owns: contacts assigned to them (assigned_user_id), plus contacts with an active agent transfer to them. This scoping is applied uniformly to listing, reading, messaging, reactions, and notes — an agent cannot read or reply to a conversation they don't own.Assignment is controlled separately:
chat.assign:write and contacts:write let a user assign or reassign conversations to agents.All outbound sends target a contact and resolve a WhatsApp account (the one specified on the request, else the contact's account, else the org's default outgoing account).
Send a plain text message. Supports replying to an earlier message for threaded context.
POST /api/contacts/{id}/messages{ "type": "text", "content": { "body": "Hi Sarah, how can we help?" }, "reply_to_message_id": "…optional…"}Images, video, audio, and documents are sent as multipart/form-data with the file, a type (image / video / audio / document), an optional caption, and an optional whatsapp_account override.
POST /api/messages/media (multipart/form-data)file=<binary> type=image caption="Your receipt" contact_id=<uuid>The chat send endpoint also sends interactive messages via the interactive field:
| Interactive type | What it sends |
|---|---|
| button | Up to a few tappable quick-reply buttons under a body text. |
| list | A list-style picker of options. |
| cta_url | A single call-to-action button that opens a URL. |
| voice_call | A WhatsApp Business Calling button that lets the customer call you. Requires the account to have Business Calling enabled. |
| flow | Launches a WhatsApp Flow form. The flow_id must belong to your organization. |
When the service window is closed — or for any structured, pre-approved outreach — send an approved template via POST /api/messages/template. You supply the template name or ID plus its body/header/button parameters. The send is rejected if the template isn't APPROVED, if required parameters are missing, or if the contact has opted out of marketing and the template is a MARKETING template. See the Messages API for the full parameter list.
React to any message with an emoji. Each user can have one reaction per message; sending an empty emoji removes your reaction.
POST /api/contacts/{id}/messages/{message_id}/reaction{ "emoji": "👍" }Opening a conversation should mark its incoming messages read to clear the unread badge:
POST /api/contacts/{id}/mark-readThis flips the contact's incoming messages to read. If the sending account has auto read receipts enabled, Whatomate also sends read receipts (the blue ticks) back to the customer over the WhatsApp API.
Notes are internal annotations on a conversation. They are stored against the contact, visible to your team in the chat view, and never sent to the customer.
chat:read can view notes; chat:write is required to create them.Endpoints (see the route table): GET / POST /api/contacts/{id}/notes, and PUT / DELETE /api/contacts/{id}/notes/{note_id}.
Each conversation is backed by a contact record you can manage from the inbox.
Assign a conversation to an agent to make ownership explicit and — for agents without contacts:read — grant them access to it. Assignment requires contacts:write.
PUT /api/contacts/{id}/assign{ "user_id": "…agent uuid…" } // null to unassignThe assignee must be a user in the same organization. Unassign by sending null.
Tags are organization-scoped, colour-coded labels. Manage the tag catalog under tags:read / tags:write / tags:delete; valid colours are blue, red, green, yellow, purple, gray. Apply tags to a contact (requires contacts:write):
PUT /api/contacts/{id}/tags{ "tags": ["vip", "billing"] }Renaming or deleting a tag in the catalog propagates the change to every contact that carries it. Filter the inbox by tag as described in Search and tag filtering.
A contact carries a phone number, profile name, WhatsApp account, tags, and a free-form metadata object. Creating and editing contacts requires contacts:write; both are audit-logged. Re-creating a previously deleted contact restores the soft-deleted record rather than erroring.
Contacts flagged marketing_opt_out cannot be sent MARKETING-category templates — such sends are rejected. This keeps bulk and promotional messaging compliant with the customer's stated preference.
When phone masking is enabled for the organization, phone numbers (and profile names that are themselves phone numbers) are masked in list and detail responses. This is an org-level privacy control applied server-side, so agents never see the raw number.
The inbox is driven by the WebSocket hub: new inbound and outbound messages, status changes (sent / delivered / read / failed), reaction updates, and note changes are all broadcast to connected clients for the organization, so the list and open conversation update without a refresh.
chat, chat.assign, contacts, and tags permissions