Ricky logorickyDocs

Inbox

Filter conversations as the inbox does, assign them in bulk, resolve handoffs, mark them unread, quote messages and fetch received files.

These operations do what the Ricky inbox does, with the same rules.

TaskOperationScope
Filter conversationsGET /conversations?…conversations:read
Assign up to 100 conversationsPOST /conversations/assignmentsconversations:write
Resolve an AI agent's handoffPOST /conversations/{id}/handoff/resolveconversations:write
Mark a conversation unreadDELETE /conversations/{id}/readconversations:write
Reply quoting a messagePOST /conversations/{id}/messagesmessages:send
Fetch the file of a received messagePOST /conversations/{id}/messages/{message_id}/mediaconversations:read

Filters

GET /conversations takes the inbox's filters. They combine; send the same ones with cursor on every page.

ParameterOnly conversations
statusopen or closed
channel_idon that channel, including earlier connections of the number
tag_idwhose contact has that tag
unread=truewith messages the team has not read
pending_handoff=truewith a handoff to a person not resolved yet
last_message_from=customerwhose latest message came from the contact
assigned_user_idassigned to that member
agent_idthat AI agent answers, with no member assigned
unassigned=truewith no member and no AI agent

assigned_user_id, agent_id and unassigned=true exclude each other: sending more than one answers 400 invalid_input. A channel or tag the organization does not have answers an empty list.

Each conversation carries unread and active_handoff, the handoff waiting or null.

Bulk assignment

POST /conversations/assignments makes members responsible for up to 100 conversations, each once. Each member also becomes the contact's owner, as when assigning one at a time.

curl -X POST https://getricky.ai/api/v1/conversations/assignments \
  -H "Authorization: Bearer $RICKY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"assignments": [{"conversation_id": "…", "assigned_user_id": "…"}]}'

The answer has one result per conversation, in order. status is assigned, not_found (the organization has no such conversation) or failed (retry that conversation). A member outside the organization refuses the whole request with 400 invalid_input before any conversation changes. See GET /members.

Handoffs

When an AI agent asks for a person to take over, active_handoff carries the reason, the summary and the responsible member. POST /conversations/{id}/handoff/resolve ends it:

  • {"resolution": "returned_to_ai"} gives the conversation back to the agent that asked and unassigns the member.
  • {"resolution": "stayed_with_human"} leaves it with the member.

A conversation with no handoff waiting answers 422 rule_violation, and so does returned_to_ai when no AI agent asked for it. The answer is the conversation with active_handoff: null.

Mark unread

DELETE /conversations/{id}/read marks it unread for the whole team. The contact sees nothing. POST on the same path marks it read.

Quote a message

On WhatsApp, a text or a file can quote a message of the same conversation with reply_to_message_id, the id from GET /conversations/{id}/messages:

{ "type": "text", "text": "Sí, ya están listos.", "reply_to_message_id": "…" }

A message of another conversation, one WhatsApp did not send, or a channel other than WhatsApp answers 400 invalid_input with param: "reply_to_message_id".

Received files

Ricky stores the file of each message it receives in the background; until then media.url is null. POST /conversations/{id}/messages/{message_id}/media stores it now from the provider and answers the message with its url, signed for one hour. A file already stored answers at once.

The provider keeps files for a limited time (about 30 days on WhatsApp). A message without a received file, or whose file the provider says expired, answers 422 rule_violation; other provider failures answer 502 upstream_error.

On this page