Skip to main content
The channels routes send outbound messages from an agent on a connected channel and expose the delivery record every send creates. They are the REST twin of the Channels runtime object: same bodies, same deliveryId, same statuses. Verified against lua-cli 3.33.0.

Base URL and authentication

Every route needs channels:send on the agent; the host, the bearer header, and the error envelope are on the REST API overview. Each send route honors an X-Idempotency-Key header: replaying a key returns the first send’s stored outcome instead of sending again, for as long as the delivery record lives; a key whose first attempt failed replays the failure; the same key from another agent is a different key.

Recipients and delivery records

A recipient is addressed by exactly one of userId, phoneNumber, email, or conversationId. userId works on every channel and resolves the address from the end user’s channel history; a raw phoneNumber only cold-starts whatsapp and sms, a raw email only email. teams, instagram, and messenger are warm-only: the end user must have written first, so address them by userId, or on Teams by conversationId to post into a shared conversation. Every send answers the same shape.
string
Id of the delivery record; stable for the send’s whole life and accepted by GET .../deliveries/:deliveryId.
string
Where the delivery stands as the call returns: accepted on a live send, or queued when the WhatsApp window was closed; receipts move it to sent, delivered, read, failed, or expired later. A replayed key returns wherever the first send has got to, so any status is possible there.
boolean
The vendor accepted the message.
boolean
The message was written to the agent’s memory. false for a conversation-scoped send, which has no single end user to record against, and on a memory write that failed after a delivered send; that case is still 200, with warning set to message delivered but not recorded to agent memory.
boolean
true when the WhatsApp 24-hour window was closed and the text waits for the end user’s reply; delivered is false until then.
string
The end user the message was recorded against, the channel-native address used, the vendor message id when the channel returns one, and a warning when something non-fatal happened.

Endpoints

POST /developer/agents/:agentId/channels/send

Sends a text message on any supported channel.
string
required
The sending agent.
string
string
required
One of whatsapp, sms, email, webchat, teams, instagram, messenger.
object
required
Exactly one of userId, phoneNumber, email, conversationId. webchat requires userId; conversationId is Teams only.
string
required
The message. It may contain ::: formatting component blocks, which each channel renders its own way.
object
channelIdentifier pins one of the agent’s channel configurations. whatsapp.onClosedWindow is queue (default: send the platform’s message-request template, queue the text, deliver when the end user replies) or fail (answer 400 so you can send your own approved WhatsApp message template). A queued send to a +1 number answers with a warning, because Meta blocks the message-request template to US numbers.
Response 200 with the send result described under Recipients and delivery records. Errors Equivalent: Channels.send().

POST /developer/agents/:agentId/channels/whatsapp/template

Sends an approved WhatsApp message template to one recipient, which is the only way to start a conversation outside the 24-hour window. The SDK’s bulk Templates.whatsapp.send() is a different route (POST /admin/agents/:agentId/channels/:channelId/whatsapp-templates/:templateId/trigger): its results[i] is Meta’s raw per-recipient response, with the message id at messages[0].id, not the send result documented here.
string
required
The sending agent.
string
Replay key.
object
required
userId or phoneNumber. A userId needs an existing WhatsApp conversation with the agent.
string
required
The template’s name as approved by Meta.
string
Template language, for example en_US.
array
Meta template components: the header, body, and button parameter values.
string
Text recorded in the agent’s memory as what the template said; a placeholder is recorded when omitted.
object
channelIdentifier pins a channel configuration.
Response 200 with the send result. Errors Equivalent: Channels.whatsapp.sendTemplate().

POST /developer/agents/:agentId/channels/whatsapp/reaction

Reacts to a WhatsApp message with one emoji.
string
required
The sending agent.
string
Replay key.
object
required
userId or phoneNumber.
string
required
The vendor id (wamid...) of the message to react to, for example an inbound message’s id from the conversation history. Meta accepts reactions on messages up to 30 days old.
string
required
A single emoji. An empty string removes the agent’s existing reaction.
object
channelIdentifier pins a channel configuration.
Response 200 with the send result. Errors Equivalent: Channels.whatsapp.sendReaction().

POST /developer/agents/:agentId/channels/email/send

Sends an email from the agent’s email channel.
string
required
The sending agent.
string
Replay key.
object
required
email for a cold address, or userId to resolve the end user’s address from their channel history.
string
Plain-text body, sent as the text/plain part.
string
Exact HTML body, sent as is with no template wrap.
string
Markdown and ::: component markers, rendered server-side into the branded email template that the agent’s own replies use. Send one of text, html, or richBody.
string
Subject line. An explicit empty string sends a subjectless email; omitting it applies the channel’s default.
string[]
Copied addresses.
string[]
Blind-copied addresses.
array
[{ filename, contentType, url }]. The bytes are fetched server-side from url; the attachments of one email may total at most 28 MiB, and a larger total answers 400 with Attachments exceed the 28MB limit.
string
The Message-ID of the email this one replies to, so mail clients thread it. Use the inbound email’s id, which agent code reads from webhookPayload.messageId; angle brackets are optional. Honored on the branded (existing-address) email channel.
string[]
The thread’s accumulated Message-ID chain.
object
channelIdentifier pins a channel configuration.
Response 200 with the send result; messageId is the mail provider’s id. Errors Equivalent: Channels.email.send().

GET /developer/agents/:agentId/channels/deliveries

Lists the agent’s recent outbound deliveries, newest first.
string
required
The agent.
string
Only deliveries addressed to this end user.
string
One of queued, accepted, sent, delivered, read, failed, expired.
string
Channel name, for example whatsapp, email, sms.
string
ISO 8601 instant; only deliveries created at or after it.
integer
default:"50"
From 1 to 200.
Response 200 with { "success": true, "data": [...] }, each item a delivery record.
string
The deliveryId.
string
Who sent it, to whom, on which channel configuration; provider is one of meta, vonage, bird, ses, agentmail, slack, front, teams, pusher.
string
channels_send for these routes; agent replies, templates, queued flushes, and notifications have their own values.
string
Current status; failed and expired are terminal.
object
On a failure: category (window_closed, unreachable, billing, opted_out, throttled, auth, template, media, invalid_request, compliance, experiment, provider, unknown), provider, the vendor code, title, detail, href, retryable, and owner (customer, recipient, lua, vendor).
array
[{ status, at, source }], one per transition; source is send, callback, or sweep.
various
The vendor id, the template used, the replay key you sent, and vendor cost metadata (Meta only).
string
ISO 8601 timestamps.
400 on an invalid filter, for example a limit outside 1 to 200 or a since that is not ISO 8601. Equivalent: Channels.listDeliveries().

GET /developer/agents/:agentId/channels/deliveries/:deliveryId

Reads one delivery record by the deliveryId a send returned.
string
required
The agent that sent it.
string
required
The delivery.
Response 200 with { "success": true, "data": <delivery> } in the shape the list route documents; 404 with No delivery <id> for agent <id> when it belongs to another agent or does not exist. Equivalent: Channels.getStatus().

See also