REST endpoints
Send a message
Send a customer message to an agent and get its answer — the same answer the chat bubble would give. Optionally streamed.
/api/v1/chatSend your API key in the Authorization: Bearer af_live_… header. See Authentication.
Body
agent_idstringrequiredmessagestringrequireduser_idstringuser_id continue the same conversation.conversation_idstringnamestringemailstringverified_emailstringstreambooleantrue to receive the answer as Server-Sent Events. Default false.Without conversation_id or user_id, every request starts a new conversation.
Request
curl https://anytimereply.com/api/v1/chat \
-H "Authorization: Bearer af_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "AGENT_ID",
"message": "Do you deliver to Sylhet?",
"user_id": "customer-123",
"name": "Rafi",
"email": "[email protected]"
}'Response
{
"conversation_id": "8b1d6c2e-…",
"message_id": "f04a…",
"text": "Yes! We deliver across Bangladesh, including Sylhet, in 2–4 days. Delivery is ৳120.",
"sources": [{ "title": "Shipping & delivery", "url": "https://example.com/shipping" }],
"confidence": 0.82,
"handoff": false,
"waiting_for_human": false,
"ui": null
}Response fields
conversation_idstringuser_id) to continue the conversation.message_idstring | nullnull when no reply was written (see below).textstringsourcesarraytitle, url). Empty when Show sources is off.confidencenumber | nullnull for Q&A, flows and small talk.handoffbooleantrue when this message handed the chat to your team.waiting_for_humanbooleantrue when your team has taken over this conversation. The AI doesn't answer; text is empty.uiobject | nullbuttons (id, type, label, url), form, replies (strings) and widgets.When your team takes over
After a handoff the conversation appears in your Helpdesk inbox. Team replies are stored in the conversation, but the API can't push them to you — read them with GET /api/v1/conversations/{id} (messages with role: "human") or listen for the handoff.requested webhook.
If the chat was paused by Guardrails (spam or a blocklist), text is empty and message_id is null.
Streaming
With "stream": true the response is text/event-stream. Each event is one data: line with JSON:
data: {"type":"meta","conversation_id":"8b1d6c2e-…"}
data: {"type":"token","t":"Yes! We "}
data: {"type":"token","t":"deliver across Bangladesh…"}
data: {"type":"done","message_id":"f04a…","text":"Yes! We deliver across Bangladesh…","sources":[…],"handoff":false,"waiting_for_human":false,"ui":null}| Event | Fields |
|---|---|
meta | conversation_id — sent first |
token | t — the next piece of text |
done | The full answer: message_id, text, sources, handoff, waiting_for_human, ui |
error | error — a readable message; the stream then ends |
const res = await fetch("https://anytimereply.com/api/v1/chat", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.ANYTIMEREPLY_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ agent_id: "AGENT_ID", message: "Hi!", user_id: "customer-123", stream: true }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const events = buffer.split("\n\n");
buffer = events.pop();
for (const e of events) {
if (!e.startsWith("data: ")) continue;
const msg = JSON.parse(e.slice(6));
if (msg.type === "token") process.stdout.write(msg.t);
if (msg.type === "done") console.log("\n", msg.sources);
}
}The final text in done can contain more than the streamed tokens (for example links added after an action) — use it as the source of truth.
Notes
- Conversations from the API appear in Chat logs with the channel
APIand fire theconversation.createdwebhook. - Each answer uses message credits like the chat bubble.
- Answers can take a few seconds (longer when actions run); allow up to 120 seconds before timing out.
Errors
| Status | Error |
|---|---|
400 | conversation_id not found for this agent · validation errors such as message: Required |
401 | Missing or invalid API key |
404 | Agent not found |
429 | Rate limit (120 requests/minute per key) |