For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Sends a first message to a phone number on WhatsApp or to an email address, and records it
as a conversation so the recipient's reply threads into it. This is the endpoint behind
the dashboard's "New message" composer. Use it when you have an address but not
necessarily a contact. If you already have a `contactId` and do not need the message in a
thread, `POST /api/whatsapp/send` and `POST /api/email/send` are the lower-level sends.
**How it works.**
1. The recipient is validated: E.164 for `whatsapp`, a valid address for `email`.
2. The contact is looked up anywhere in the workspace. Email matching ignores case; WhatsApp
matches `whatsapp_number` exactly. An unknown recipient is created in the workspace's
"Manual Conversations" campaign. A contact already enrolled elsewhere is **not** moved.
3. The message is delivered through the channel's provider, with every guard of the
lower-level send applied (compliance, opt-out, 24-hour window, daily cap).
4. Only after delivery succeeds is the conversation found, reopened or created, using the
same thread key inbound messages use, and the message stored with
`metadata.manual = true`.
On WhatsApp, pass `templateId` to reach a contact outside WhatsApp's 24-hour window. `message` is
then optional, and the thread records `[template] <templateId>` as the content. On email,
`subject` is required. `webchat`, `instagram` and `messenger` cannot be started from here.
**Side effects.** Sends a real WhatsApp message or a real email from the
workspace's connected mailbox. Consumes one unit of the channel's daily send cap. The unit
is refunded if the provider rejects the send. It does **not** draw on the AI-message
allowance. The AI reply to the contact's answer does. May create a contact, and the "Manual
Conversations" campaign on first use. Broadcasts a realtime update to the dashboard and
writes an audit entry.
**Idempotency.** Not idempotent. A retry after a timeout delivers the message a second time.
The conversation row is reused, so both copies land in the same thread. Check
`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–600 requests/min per workspace by plan) **and** the configuration-mutations limiter — 10 requests/min per workspace, a budget shared with other configuration mutations. See [Rate limits](/rate-limits).
- **Plan:** Available on every plan. The workspace needs at least one agent, a WhatsApp sender that is `ONLINE` for WhatsApp, and a connected mailbox for email.
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).
Request
message is required unless channel is whatsapp and templateId is sent.
subject is required when channel is email. Strings are trimmed before validation.
recipientstringRequired1-254 characters
Who to write to. An E.164 phone number (+ and country code) for whatsapp; an
email address for email. An invalid value returns 400 with
Phone number must be E.164 format (e.g. +14155551234) or Invalid email address.
channelenumRequired
Channel to start the conversation on.
- `whatsapp`: sent from the workspace's WhatsApp sender.
- `email`: sent from the workspace's connected Gmail, Outlook or Zoho Mail mailbox.
Allowed values:
messagestringOptional1-4096 characters
Text of the message, sent exactly as written. Required unless a WhatsApp
templateId is sent. On WhatsApp freeform text is only accepted inside the
24-hour window.
subjectstringOptional1-998 characters
Email subject. Required when channel is email; ignored on WhatsApp.
templateIdstringOptionalformat: "uuid"
WhatsApp only. Id of one of the workspace’s WhatsApp templates. It must be
approved, or the call fails with 422 TEMPLATE_NOT_APPROVED. Templates can be
sent regardless of the 24-hour window.
templateVariableslist of strings or map from strings to stringsOptional
Values for the template placeholders. Either an ordered list, where the first item
fills {{1}}, or an object keyed by placeholder number. Ignored without templateId.
Response
Message delivered and recorded in the conversation.
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
502
Bad Gateway Error
Sends a first message to a phone number on WhatsApp or to an email address, and records it
as a conversation so the recipient’s reply threads into it. This is the endpoint behind
the dashboard’s “New message” composer. Use it when you have an address but not
necessarily a contact. If you already have a contactId and do not need the message in a
thread, POST /api/whatsapp/send and POST /api/email/send are the lower-level sends.
How it works.
The recipient is validated: E.164 for whatsapp, a valid address for email.
The contact is looked up anywhere in the workspace. Email matching ignores case; WhatsApp
matches whatsapp_number exactly. An unknown recipient is created in the workspace’s
“Manual Conversations” campaign. A contact already enrolled elsewhere is not moved.
The message is delivered through the channel’s provider, with every guard of the
lower-level send applied (compliance, opt-out, 24-hour window, daily cap).
Only after delivery succeeds is the conversation found, reopened or created, using the
same thread key inbound messages use, and the message stored with
metadata.manual = true.
On WhatsApp, pass templateId to reach a contact outside WhatsApp’s 24-hour window. message is
then optional, and the thread records [template] <templateId> as the content. On email,
subject is required. webchat, instagram and messenger cannot be started from here.
Side effects. Sends a real WhatsApp message or a real email from the
workspace’s connected mailbox. Consumes one unit of the channel’s daily send cap. The unit
is refunded if the provider rejects the send. It does not draw on the AI-message
allowance. The AI reply to the contact’s answer does. May create a contact, and the “Manual
Conversations” campaign on first use. Broadcasts a realtime update to the dashboard and
writes an audit entry.
Idempotency. Not idempotent. A retry after a timeout delivers the message a second time.
The conversation row is reused, so both copies land in the same thread. Check
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–600 requests/min per workspace by plan) and the configuration-mutations limiter — 10 requests/min per workspace, a budget shared with other configuration mutations. See Rate limits.
Plan: Available on every plan. The workspace needs at least one agent, a WhatsApp sender that is ONLINE for WhatsApp, and a connected mailbox for email.
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.
Channel to start the conversation on.
whatsapp: sent from the workspace’s WhatsApp sender.
email: sent from the workspace’s connected Gmail, Outlook or Zoho Mail mailbox.