Skip to content

Ask AI

Ask anything about Destesi — setup, products, APIs.

AI answers may be wrong — always verify against the docs.

Inbox reference

Base URL: https://api.inbox.destesi.io

Browser session. Signing in through SSO sets a host-only __Host-inbox_session cookie on the API host. This is what the web app uses; send it with credentials included.

Personal Access Token. For the CLI, scripts and MCP, send an identity PAT plus the workspace slug:

Authorization: Bearer idn_pat_…
X-Destesi-Workspace: acme-co

A PAT acts as its user, with that user’s role and permissions in the workspace. See CLI & API auth for minting one.

Each endpoint below names what it needs:

  • view, reply, start, note, assign, quick — the conversations.view, conversations.reply, conversations.start, conversations.note, conversations.assign and quick_replies.manage permissions. A refusal is 403 permission_required.
  • admin — a workspace owner or admin. A refusal is 403 admin_required.
  • member — any member of the workspace.

contacts.details never refuses a request. Without it, the parts it covers are left out of the answer. See Inbox concepts.

Beyond permissions, a non-admin sees only the conversations inside their queue and connection fences. Anything outside them answers 404.

Field Values
provider whatsapp, messenger
status open, closed
mode automated, human
audience customer, operator
Message direction inbound, outbound
Message author customer, agent, human, merchant_device, system
Message kind text, template, interactive, note, image, video, audio, document, sticker
Message delivery_state received, pending, sent, delivered, read, failed, unknown, internal
Channel key <provider>:<channel_address>, e.g. whatsapp:1234567890

operator conversations archive messages a connected app exchanged with your own staff. They are left out of every list unless you pass audience=operator, and replying to one is 409 operator_thread.

Field Meaning
id Conversation id
provider, channel_address, business_number The connection it arrived on
peer_address, peer_name The customer’s address and channel profile name
peer_phone The phone an operator filed for this person, "" if none
status, mode, audience See the vocabularies
automation_epoch Moves on every takeover and hand-back
answerer The app answering automated conversations; "" means people answer
assignee_user_id, queue_id "" when unassigned or in no queue
unread Unread messages for the caller
last_sequence, last_message_preview, last_message_at The latest message
last_message_state Delivery state of the latest message when you sent it; "" when the customer did
last_inbound_at When the customer last wrote
window_open Whether free text can be sent now
templates, media Whether this channel carries templates and attachments
tags The conversation’s tags

Messages carry id, sequence, direction, author, author_user_id, kind, body, delivery_state, failure_reason, occurred_at, and, when present, has_media with media_mime, media_filename and media_size, reply_to (the quoted message) and reaction (the customer’s emoji).

Lists answer {"items": [...], "next_cursor": "..."}; pass cursor to get the next page. Pages hold 50 by default; limit goes up to 200, and anything above falls back to 50.

Method Path Needs Purpose
GET /healthz Public Liveness
GET /v1/sso/callback Public SSO landing; sets the session cookie
GET /v1/auth/me Session The signed-in user, role and permissions
POST /v1/auth/logout — Clears the session. Idempotent
GET /v1/me/products Session Launcher entitlements, from identity
GET /v1/me member Your user id, role, Inbox permissions, and queue and connection fences
Method Path Needs Purpose
GET /v1/conversations view List, most recent first
POST /v1/conversations reply + start Write first: open a conversation with a template
GET /v1/conversations/start-channels view Connections you may write first from
GET /v1/conversations/unread view Unread counts: unread and per view views.{all,mine,queue,closed}
GET /v1/conversations/{id} view One conversation
GET /v1/conversations/{id}/messages view Messages; before_seq, limit
POST /v1/conversations/{id}/read view Mark read, optionally up to sequence
POST /v1/conversations/{id}/messages reply Reply {text}
POST /v1/conversations/{id}/attachments reply Send a file (see below)
POST /v1/conversations/{id}/template-messages reply + start Send a template {name, language, params}
POST /v1/conversations/{id}/notes note Internal note {text}
POST /v1/conversations/{id}/take-over reply Switch to human; self-assign if unassigned
POST /v1/conversations/{id}/hand-back reply Switch to automated
POST /v1/conversations/{id}/close reply Close
POST /v1/conversations/{id}/reopen reply Reopen
POST /v1/conversations/{id}/assign assign, or reply for yourself {user_id?, queue_id?}
PUT /v1/conversations/{id}/tags reply Replace the tags: {tag_ids}, at most 10
GET /v1/conversations/{id}/messages/{mid}/media view {url, mime, filename, size} for an attachment

GET /v1/conversations filters, combined with AND:

Param Meaning
view mine, queue, closed; anything else lists every open conversation
queue_id With view=queue, only this queue
q Search over name, number, filed phone and last message
peer Exact customer address: every conversation with that person, open or closed, and view is ignored
tag Tag id
channel Channel key; repeat for several
waiting 1: open, the customer spoke last, and a person owes the answer
audience operator to list operator conversations

Use peer, not q, to find the conversation for a phone number. q is a fuzzy search and never picks “the” conversation.

On assign, an absent field is left unchanged and "" clears it. Assigning only yourself needs conversations.reply; anything else needs conversations.assign.

Write first takes {peer_address, template, language, params, name, provider, channel_address}. peer_address and template are required; provider defaults to whatsapp; channel_address is needed only when you work more than one connection. The number may be typed with spaces, dashes or a leading +.

Attachments take either a multipart form {file, caption} (the web) or JSON {drive_file_id, caption, filename} naming a file already in the workspace’s Drive. Up to 16 MB, caption up to 1024 characters.

Method Path Needs Purpose
GET /v1/contacts view One row per person; q, channel, no_phone=1, cursor, limit
PUT /v1/contacts/{peer} reply File a name and/or phone: {name?, phone?}
GET /v1/conversations/{id}/contact view What connected apps know about the person, as {contact}
GET /v1/conversations/{id}/customer view A connected app’s customer sheet for the person
GET /v1/conversations/contact-names?ids= view Display names for up to 100 conversations

A contact row carries peer_address, name, renamed, phone, providers, threads, open, first_seen and last_message_at, plus contact (email, document, address…) when you have contacts.details and an app knows them.

On PUT /v1/contacts/{peer}, an absent field is unchanged and "" clears it. A phone must have 7 to 15 digits and is stored as digits. The person must have a conversation you can see.

The contact and customer routes answer 404 contact_not_found / 404 customer_not_found when no app knows the person, when the conversation is on Messenger, and when you lack contacts.details.

Method Path Needs Purpose
GET /v1/conversations/order-context?ids= view Order context for up to 100 conversations
GET /v1/conversations/suggestions?ids= view Suggestions from every app set up in the workspace
POST /v1/conversations/{id}/suggestions/{app}/{sid}/open view The app’s page for a suggestion, as a relative path
POST /v1/conversations/{id}/suggestions/{app}/{sid}/dismiss reply Dismiss a suggestion

No app, or an app that does not answer, gives an empty list rather than an error.

Method Path Needs Purpose
GET /v1/templates view Templates with Meta’s status, required per app, accounts, connected
POST /v1/templates admin Submit a template for Meta’s review
POST /v1/templates/ensure admin Retry creating an app’s required templates: {app}

POST /v1/templates takes {name, language, category, body, header, footer, examples, buttons, account_id}:

Field Rule
name Lowercase letters, digits and underscores
language Required, e.g. es
category UTILITY or MARKETING
body 1–1024 characters, variables written {{1}}, {{2}}…
examples One per variable, in order
header, footer Up to 60 characters each
buttons Up to 3 quick-reply labels, 25 characters each
account_id The WhatsApp Business account; empty uses the first

It answers 201 with {name, status, id}; the status is Meta’s, usually PENDING. A required template with no match on the account is MISSING.

Method Path Needs Purpose
GET /v1/queues member Queues with member_user_ids
POST /v1/queues admin Create {name, color}
PATCH /v1/queues/{id} admin Rename or recolour
DELETE /v1/queues/{id} admin Delete; its conversations stay, in no queue
PUT /v1/queues/{id}/members admin Replace members: {user_ids}
GET /v1/tags member Tags
POST /v1/tags admin Create {name, color}
PATCH /v1/tags/{id} admin Rename or recolour
DELETE /v1/tags/{id} admin Delete; removed from every conversation. 204
GET /v1/quick-replies view Quick replies
POST /v1/quick-replies quick Create {shortcut, body, image_drive_file_id?}; body may be empty when an image is set
PATCH /v1/quick-replies/{id} quick Change shortcut, body and/or image_drive_file_id ("" removes the image)
POST /v1/quick-replies/image quick Multipart {file}, a JPG or PNG up to 5 MB → {drive_file_id}
GET /v1/quick-replies/{id}/image view The reply’s image bytes
DELETE /v1/quick-replies/{id} quick Delete

Tag names are 1–40 characters and unique per workspace ignoring case; a colour is #rgb, #rrggbb or empty. Quick-reply shortcuts are unique per workspace ignoring case, and a leading / is dropped.

Method Path Needs Purpose
GET /v1/settings member The workspace’s Inbox settings
PUT /v1/settings admin Partial update; absent fields stay
GET /v1/channels view Connected accounts, and which ones Inbox receives
POST /v1/channels admin Receive an account: {channel_account_id}
DELETE /v1/channels/{id} admin Stop receiving an account. It stays connected in Connect
GET /v1/channel-access admin The connections Inbox has received on, and who works each
PUT /v1/channel-access/{user_id} admin Replace one member’s connections: {channel_keys}

Settings fields:

Field Meaning
bot_app The answering app; "" means people answer, null means never chosen
bot_apps The apps set up in this workspace (read only)
greeting_message Sent to a newly created conversation
away_message Sent outside business hours, at most every 12 hours per conversation
business_hours {"timezone": "America/Bogota", "days": {"mon": [{"from": "09:00", "to": "18:00"}]}}
default_queue_id The queue new conversations land in

Weekday keys are sun to sat. Send only the fields you change: echoing the whole document back would turn a null answerer into an explicit "".

On PUT /v1/channel-access/{user_id}, an empty list lifts the restriction; it never means “no connections”. Each key must be one GET /v1/channel-access lists. The answer includes released, the number of that member’s conversations handed back because they lost the connection.

Method Path Needs Purpose
POST /v1/chat Session Streams NDJSON events, ending with done or error

The request body is {"messages": [{"role": ..., "content": ...}]}, the whole conversation so far. Its tools are the MCP tools below without the inbox_ prefix, each calling the same route with your permissions. Each turn draws on the workspace’s credits.

Errors are {"error": "code"}, sometimes with a detail. A credit refusal uses the suite’s quota envelope, {"error": {"code": "quota_exceeded", ...}}.

Code Status Meaning
missing_session 401 No cookie and no bearer
session_invalid 401 Cookie rejected by identity; it is cleared
unknown_bearer_scheme 401 Bearer is not an idn_pat_ PAT
missing_workspace_header 401 PAT sent without X-Destesi-Workspace
invalid_token 401 PAT unknown, or not a member of that workspace
csrf_rejected 403 Cookie mutation from an untrusted origin
product_forbidden 403 The workspace does not let you into Inbox
permission_required 403 Your role lacks the named permission
admin_required 403 Owner or admin only
not_found 404 Unknown id, another workspace’s, or outside your fences
contact_not_found / customer_not_found 404 No app knows this person, or they are hidden from you
invalid_json 400 Body is not JSON
too_many_ids 400 More than 100 conversation ids
window_closed 409 More than 24 hours since the customer last wrote
no_answering_bot 409 Hand back with people answering
operator_thread 409 Replying to an operator conversation
tag_exists 409 A tag with that name already exists
conflict 409 Duplicate, e.g. a quick-reply shortcut
whatsapp_not_connected 409 No WhatsApp account connected for templates
text_required 422 Empty reply or note
name_required 422 Missing template, queue or tag name
peer_and_template_required 422 Write first without a number or template
channel_cannot_start 422 Write first on a channel with no templates (Messenger)
templates_unsupported 422 Template on a channel with no templates
media_unsupported 422 Attachment on a channel with no attachments
channel_required 422 Several connections; name one
unknown_channel 422 That connection is not one you may write from
no_channel 422 No connection to write from
assignee_out_of_scope 422 The assignee does not work this conversation’s connection
queue_out_of_scope 422 Every member of that queue works other connections
unknown_channel_key 422 A channel key Inbox has never received on
unknown_tag / too_many_tags / tag_ids_required 422 Tag set problems
invalid_name / invalid_color 422 Tag name or colour out of range
invalid_phone 422 Not 7–15 digits
name_or_phone_required 422 Contact update with neither field
shortcut_and_body_required 422 Quick reply missing a field
unknown_drive_file 422 Not a file in this workspace’s Drive
caption_too_long 422 Caption over 1024 characters
invalid_business_hours 422 business_hours is not the expected shape
unknown_bot_app / unknown_app 422 Not an app this deployment or workspace has
account_not_selected 422 That WhatsApp Business account is not behind Inbox’s numbers
invalid_name, invalid_language, invalid_category, invalid_body_length, invalid_header_length, invalid_footer_length, invalid_button_length 422 Template outside Meta’s limits; detail explains
attachment_too_large 413 Over 16 MB
media_expired 410 The provider no longer holds a received file that was never copied
no_media 404 The message has no attachment
quota_exceeded 429 The workspace is out of credits for the assistant
template_rejected 502 Meta refused the template; detail says why
connect_unavailable / provider_error / media_unavailable / upload_failed 502 Connect, Meta or Drive failed
identity_unavailable 502 Identity could not be reached
connect_unconfigured 503 This deployment has no Connect wiring
attachments_disabled 503 This deployment has no Drive wiring
chat_disabled 503 No AI model selected for Inbox
store_unavailable 503 No database configured

A send refused by Connect or the provider passes Connect’s status and body through.

Available to an AI agent on Destesi’s hosted MCP server at https://mcp.destesi.io/sse, and on any mcp binary you run yourself with INBOX_API_URL set. See MCP. Every tool takes a workspace slug and runs with your PAT’s permissions.

Tool Purpose
inbox_list_conversations List with view, queue_id, q, peer, tag, channel, waiting
inbox_start_conversation Write first with a template
inbox_get_conversation One conversation
inbox_list_messages Messages, paged by before_seq
inbox_mark_read Mark read
inbox_reply Send text; takes the conversation over
inbox_send_attachment Send a Drive file
inbox_send_template Send an approved template
inbox_add_note Internal note
inbox_take_over Pause the bot on a conversation
inbox_hand_back Return a conversation to the bot
inbox_close_conversation Close
inbox_reopen_conversation Reopen
inbox_assign_conversation Assign to a person and/or queue
inbox_list_contacts The contact list
inbox_rename_contact File a contact’s name and/or phone
inbox_list_templates Templates and required templates
inbox_create_template Submit a template for review
inbox_ensure_templates Retry an app’s required templates
inbox_list_queues Queues and members
inbox_create_queue Create a queue
inbox_update_queue Rename or recolour a queue
inbox_delete_queue Delete a queue
inbox_set_queue_members Replace a queue’s members
inbox_list_tags Tags
inbox_create_tag Create a tag
inbox_update_tag Rename or recolour a tag
inbox_delete_tag Delete a tag
inbox_set_conversation_tags Replace a conversation’s tags
inbox_list_channel_access Connections and who works each
inbox_set_member_channels Replace one member’s connections
inbox_list_quick_replies Quick replies
inbox_create_quick_reply Create a quick reply
inbox_update_quick_reply Change a quick reply
inbox_delete_quick_reply Delete a quick reply
inbox_get_settings Settings
inbox_set_settings Change settings
inbox_list_channels Connected accounts and which Inbox receives
inbox_select_channel Make Inbox receive an account
inbox_deselect_channel Stop Inbox receiving an account

dst inbox needs an identity PAT and a workspace. See CLI for install and login.

Terminal window
dst inbox conversations --view mine
dst inbox conversations --waiting --channel whatsapp:1234567890
dst inbox conversations --peer "+57 300 111 2233"
dst inbox conversation get <id>
dst inbox conversation messages <id> --limit 20
dst inbox conversation reply <id> "Your order ships today."
dst inbox conversation template <id> --name order_update --language es --param 1234
dst inbox conversation attach <id> <drive_file_id> --caption "Invoice"
dst inbox conversation note <id> "Customer prefers a call."
dst inbox conversation take-over <id> # also: hand-back, close, reopen, read
dst inbox conversation assign <id> --user <user_id> --queue ""
dst inbox conversations start "+57 300 111 2233" --template welcome --language es --name "Ana"
dst inbox contacts list --no-phone
dst inbox contacts rename <peer> "Ana Gómez"
dst inbox contacts phone <peer> "+57 300 111 2233"
dst inbox templates list
dst inbox templates create --name order_update --language es --category UTILITY \
--body "Your order {{1}} is on its way" --example 1234
dst inbox templates ensure commerce
dst inbox queues list # also: create, update, delete, members
dst inbox tags list # also: create, update, delete, set
dst inbox quick-replies list # also: create, update, delete
dst inbox settings get
dst inbox settings set --greeting "Hi! We'll be right with you."
dst inbox channels list # also: select, deselect
dst inbox channel-access list # also: set <user_id> [key...], --clear

Every subcommand takes -o json and -w <workspace>. On assign, settings set, and the update verbs, only the flags you pass are sent, and "" clears a value. The base URL is derived from your configured API URL and can be overridden with --inbox-api-url or DESTESI_INBOX_API_URL.