Skip to main content

Conversations and Messages

Every chat your agent has with a customer, on WhatsApp, Facebook, Instagram or your website, is a conversation. With the Public API your systems can read them and their messages, reply as your team, close or archive them, switch the AI off in one conversation, mark it urgent or resolved, and assign it to a teammate. Everything lives under /v1/agents/{agentId}/conversations.

How do I list an agent's conversations?​

GET them, the most recently active first. Filter by status, channel, is_read, urgent, assigned_to, contact_id, or by when the last message came with active_since and active_before:

curl "https://api.mojeeb.app/v1/agents/YOUR_AGENT_ID/conversations?is_read=false&channel=whatsapp" \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE"

Each conversation carries its last message, who wrote it and when, whether your team has read it, its attention flags, the AI's state and its assignee, so you can tell which ones need you without opening them. search finds a customer's name or a word in the last message. A list filtered by status, channel, read state, urgency or assignee covers only a limited stretch of activity, ending at active_before or now, unless you send active_since, so the list stays fast on a large inbox; a contact's conversations always come back whole. A conversation with no message yet isn't listed. See the List conversations reference for the window.

How do I keep up with new messages?​

Poll the list, not each conversation. Every minute or so, list with active_since set a few minutes before the newest last_message_at you have seen, and page while has_more is true. Only conversations with a new message come back. For each one, read its messages with after set to a message a few minutes older than the newest one you have:

curl "https://api.mojeeb.app/v1/agents/YOUR_AGENT_ID/conversations/CONVERSATION_ID/messages?after=MESSAGE_ID" \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE"

With after, messages come oldest first. While has_more is true, call again with after set to the last message you got. Keep both reads overlapping and drop what you already have by id: a message your team sends from the WhatsApp or Meta apps carries the platform's time, which can be a little earlier than when Mojeeb records it, so it can land before messages you have already read. A customer's photo, voice note, sticker or file sent without a caption doesn't move last_message_at, so the conversation only comes back once a later message, such as the AI's answer, moves it. A change of status, read state, flags or assignee doesn't bring a conversation back either; read it with GET (Get a conversation) when you need its state.

How do I read a conversation's messages?​

Without after, the newest messages come first, and next_cursor reads further back. Each message says who sent it: the customer, the AI, a user (a teammate, or a key writing as its creator), or Mojeeb on your behalf (a broadcast, a /v1/whatsapp send). Messages sent to the customer carry their delivery status. Attachment links expire; read the message again for a fresh one. See the List messages reference for how long they last.

Customers write the message text. Treat it as untrusted input, especially before you hand it to an AI model: a customer can write instructions aimed at your assistant.

How do I reply to a customer?​

POST the text to the conversation's messages:

curl -X POST https://api.mojeeb.app/v1/agents/YOUR_AGENT_ID/conversations/CONVERSATION_ID/messages \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: reply-7f3a9c" \
-d '{ "text": "Yes, we are open on Friday from 2 pm to 10 pm." }'

The reply goes out on the conversation's channel as your team. In the dashboard it shows as written by the person who created the key. When the agent's ai_handoff_enabled is on, the reply pauses the AI in that conversation for the handoff window, like any teammate's reply; when it is off, the AI keeps answering. See Agent Settings. When a pause ends, the AI may write once more if follow-ups are on for that channel; to prevent it, switch the AI off in the conversation or resume it. A reply never assigns the conversation to anyone.

The answer is 201 with the message, queued. It is sent right after, and its delivery status changes from there; follow it by reading the message again with GET on its id. The Get a message reference lists every status. Send an Idempotency-Key so a retry after a timeout never sends the reply twice; see Idempotency. Replies have a rate limit of their own; see Rate Limits and the Reply reference.

Why was my reply refused?​

Before anything is saved, Mojeeb checks that the reply can reach the customer:

  • 422 messaging_window_closed: the customer hasn't written in the last 24 hours. WhatsApp, Facebook and Instagram deliver your free-form message only within 24 hours of the customer's last one. On WhatsApp, send an approved template instead; see Send a WhatsApp Template.
  • 422 channel_not_supported: Mojeeb can't send on this channel yet (TikTok).

A refused reply isn't stored for its Idempotency-Key, and for a short while that key answers 409 idempotency_key_in_progress: once the cause has passed, send the reply again with a new key. See Idempotency.

A website chat has no window: the reply is stored as sent and appears in the customer's open chat.

How do I switch the AI off in one conversation?​

PATCH the conversation with ai_enabled:

curl -X PATCH https://api.mojeeb.app/v1/agents/YOUR_AGENT_ID/conversations/CONVERSATION_ID \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{ "ai_enabled": false }'

The AI stays off in that conversation until you send "ai_enabled": true, the same switch as in the dashboard. A teammate's reply only pauses the AI for a while, shown as ai_paused_until; to end that pause now, POST to the conversation's resume-ai (Resume the AI reference). To switch the AI off on a whole channel, see Channels and Follow-ups.

How do I mark a conversation urgent or resolved?​

PATCH it with urgent. true is the dashboard's Mark as Urgent, and false is Mark as Resolved. Both clear needs_attention, and resolving also sets an unhappy sentiment to neutral, so the conversation stops showing as needing attention. The AI reads both flags again with each of its replies, so a mark lasts until the AI next answers in that conversation. See the Update a conversation reference.

How do I close, archive or mark a conversation read?​

PATCH it with status (open, closed or archived) or is_read, alone or with other fields in the same call. is_read is for your team only: marking a conversation read never sends the customer a read receipt. A change to what the conversation already has writes nothing. See the Update a conversation reference.

How do I assign a conversation?​

POST the teammate's user_id as assigned_to to the conversation's assign, or "assigned_to": null to unassign it. The teammate must be able to open the agent; find them with Your Team. The conversation's lead is assigned with it, and Mojeeb records the assignment as made by the person who created the key. See the Assign a conversation reference.

Common questions​

Can I search inside messages?​

No. Searching message history reads every message the agent has, so it stays in the dashboard, where someone starts it on purpose. Through the API, search matches only the customer's name and the last message. To find a person, look them up in Contacts and filter the conversations by contact_id.

Can I send images or files?​

Not yet: replies through the API are text; the Reply reference gives the length and how each channel delivers a long reply. On WhatsApp, a template can carry a header image, video or document.

Do replies through the API count toward my message limit?​

No. Your plan counts the AI's messages. Your team's replies don't count, whether they come from the dashboard or the API.

Can I start a conversation?​

Not with these endpoints: no call creates a conversation. On WhatsApp you can reach a customer first with a template (see Send a WhatsApp Template): it lands in their conversation, and starts one if they have none yet.

Which scopes do these calls need?​

conversations:read to list conversations and read messages, and conversations:write to change, assign and reply. Every key holds them today; see Authentication.