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. The agent still answers the contact's next inbound message as usual. **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:** refused with 422. Dashboard replies are not available there yet. 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](/webhooks). **Access** - **Required scope:** `write`. - **Rate limit:** General API — 120 requests/min per workspace (Starter), 200 (Growth), 300 (Business), 600 (Enterprise). See [Rate limits](/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. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | 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](/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