Skip to navigation

Send an operator reply

View as Markdown

Adds a reply written by a person to an existing conversation. This is the human takeover path. The AI agent is not invoked for this reply and does not answer on top of it. On WhatsApp, email and webchat the agent still answers the contact’s next inbound message as usual. On Instagram and Messenger the agent steps back after a human reply (see below).

Delivery depends on the thread’s channel.

  • WhatsApp: delivered before anything is stored. If WhatsApp refuses (24-hour window, opt-out, compliance, cap), nothing is written and the refusal is returned. Pass templateId instead of message when the contact is outside the 24-hour window.
  • Email: sent from the workspace’s connected mailbox, then stored. The subject is taken from the thread (latest recorded subject, prefixed Re: once), falling back to Re: su conversación.
  • Webchat: stored and pushed to the visitor’s open widget in real time. A visitor without an open widget sees it the next time the history loads.
  • Instagram / Messenger: delivered through the Facebook Page the person wrote to, before anything is stored. Within 24 hours of the person’s last message it is sent as a normal response. After 24 hours and within 7 days it is sent as a human-agent message, which Meta only accepts once the Human Agent feature is approved for the app. After 7 days, or when the person has never written, it is refused with 422. A long reply is split into several messages (Instagram accepts 1,000 bytes per message, Messenger 2,000 characters). Every refusal (window closed, person blocked the Page, Instagram message access switched off, another app controls the thread, contact opted out, daily cap) returns 4xx with the reason in error.message, and nothing is written.

Human takeover on Instagram and Messenger. After a human reply on these two channels the agent stops answering that thread for 24 hours from the last human message. The same happens when someone answers from the Page inbox in Meta Business Suite. While it lasts, the contact’s messages are still stored (with metadata.held_for_human = true), the conversation is flagged as waiting for a person, and metadata.human_takeover on the conversation holds { until, source, at }. POST /api/conversations/{conversationId}/needs-human/resolve hands the thread back to the agent.

The stored message has role: agent and metadata.manual = true (plus provider_message_id and template_id when applicable). Template replies are recorded as [template] <templateId>.

Side effects. Sends a real WhatsApp message or email to the customer. Provider-backed sends consume one unit of the channel’s daily cap. Replies written by people never draw on the AI-message allowance. Broadcasts realtime updates to the dashboard and the visitor’s widget, clears the conversation caches, and writes an audit entry.

Idempotency. Not idempotent. A retry after a timeout sends and stores the reply twice. Re-read the thread with GET /api/conversations/{conversationId} before retrying.

Webhook events. audit.log_recorded for subscribers that selected it explicitly. See Webhooks.

Access

  • Required scope: write.
  • Rate limit: General API — 120 requests/min per workspace (Starter), 200 (Growth), 300 (Business), 600 (Enterprise). See Rate limits.
  • Plan: Available on every plan.

Authentication

AuthorizationBearer

Workspace API key: jl_ followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (Settings → API Keys) and sent as Authorization: Bearer jl_.... The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys.

ScopeGET / HEADPOST / PUT / PATCH / DELETEAdmin-only routes
readYesNoNo
writeYesYesNo
fullYesYesYes

Operations restricted to admins or owners reject keys without the full scope with 403, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See Authentication.

Path parameters

conversationIdstringRequiredformat: "uuid"
Id of the conversation to reply on. A value that is not a UUID returns 400.

Request

At least one of message or templateId is required. When both are sent on WhatsApp, the template is sent.

messagestringOptional1-4096 characters

Reply text, trimmed and sent as written. Required unless templateId is sent. Email threads always need message.

templateIdstringOptionalformat: "uuid"

WhatsApp conversations only. Id of an approved template of the workspace, for contacts outside the 24-hour window. On any other channel the call returns 400 templateId is only supported on WhatsApp conversations.

templateVariableslist of strings or map from strings to stringsOptional

Values for the template placeholders, as an ordered list ({{1}} first) or an object keyed by placeholder number. Ignored without templateId.

Response

Reply delivered (for WhatsApp and email) and stored.

dataobject

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
404
Not Found Error
409
Conflict Error
422
Unprocessable Entity Error
423
Locked Error
429
Too Many Requests Error