ClearMakes AgentsAPI reference

Talk to an agent from your own application

Two endpoints: one starts a conversation, one continues it. Both stream the reply back as server-sent events, so you can render the answer as it is written rather than waiting for it.

No API key is involved. An agent's id is its capability — anyone holding it can talk to that agent, exactly as a visitor to your website can. Treat it as public, and pause the agent from its Publish page when you want it to stop answering. Your agent id is on that same page.

Start a conversation

POST /api/v1/chats/with-message

Creates the conversation and answers the first message in one call. The response is an SSE stream, not JSON — the first event carries the chat_id you need in order to continue.

contentstring, requiredThe visitor's message.
chatbot_iduuidWhich agent answers. Without it the request is not attached to any agent.
titlestringA label for the conversation in your dashboard. Generated for you if omitted.
page_contextobjectWhere the visitor is on your site, so the agent can take the current page into account.
curl -N -X POST https://chatly.analytos.ai/api/v1/chats/with-message \
  -H "Content-Type: application/json" \
  -d '{"chatbot_id": "YOUR_AGENT_ID", "content": "What are your opening hours?"}'

-N matters: without it curl buffers the response and the stream looks like it arrives all at once at the end.

Continue a conversation

POST /api/v1/chats/{chat_id}/messages/stream

Sends the next message in an existing conversation. Use the chat_id from the chat_created event. Earlier turns are already in the agent's context — send only the new message.

curl -N -X POST https://chatly.analytos.ai/api/v1/chats/CHAT_ID/messages/stream \
  -H "Content-Type: application/json" \
  -d '{"content": "And on weekends?"}'

Stream events

Every line is data: followed by one JSON object with a type. Read token and done; the rest are there if you want to show progress, and can be ignored safely. Treat an unknown type as something to skip — more may be added.

chat_createdchat_idFirst event of a new conversation. Keep this id.
tokencontentOne piece of the answer. Append them in order to build the reply.
sourcessources[]Which knowledge documents the answer drew on.
statusstepWhat the agent is doing — for example classifying_intent.
tool_statuslabelA human-readable note that a connected app is being used.
tool_callscalls[]Which tools ran, with the arguments they were given.
intentintent, confidenceHow the question was classified.
chartspecA chart to render, when the agent answered with data.
generated_imageimage_urlAn image the agent produced.
donemessage_id, chat_titleThe answer is complete. Stop reading.
errormessageThe turn failed. No done follows.
data: {"type": "chat_created", "chat_id": "4cff03c1-..."}
data: {"type": "status", "step": "classifying_intent"}
data: {"type": "sources", "sources": [{"title": "handbook.md"}]}
data: {"type": "token", "content": "We are open "}
data: {"type": "token", "content": "9 to 5, Monday to Friday."}
data: {"type": "done", "message_id": "8f1c...", "chat_title": "Opening hours"}

Reading the stream in JavaScript:

const res = await fetch("https://chatly.analytos.ai/api/v1/chats/with-message", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ chatbot_id: AGENT_ID, content: "Hello" }),
})

const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ""
let answer = ""

while (true) {
  const { value, done } = await reader.read()
  if (done) break
  buffer += decoder.decode(value, { stream: true })

  // Events are newline-delimited; the last piece may be incomplete.
  const lines = buffer.split("\n")
  buffer = lines.pop() ?? ""

  for (const line of lines) {
    if (!line.startsWith("data: ")) continue
    const event = JSON.parse(line.slice(6))
    if (event.type === "token") answer += event.content
    if (event.type === "done") return answer
    if (event.type === "error") throw new Error(event.message)
  }
}

Agent appearance

GET /api/v1/chatbots/{agent_id}/widget-config

The agent's public presentation — display name, greeting, avatar, colours and which features are switched on. Use it to make your own interface match what you set under Appearance. It returns only what a visitor is meant to see; instructions, knowledge and credentials are never included.

curl https://chatly.analytos.ai/api/v1/chatbots/YOUR_AGENT_ID/widget-config

Errors

Failures before the stream starts are ordinary JSON with a detail. Once the stream has started, a failure arrives as an error event instead, and no done follows it.

403ForbiddenThe agent is paused. It answers nobody until it is activated again from its Publish page.
404Not foundNo such agent or conversation — or it was deleted.
422UnprocessableThe body is missing something, usually content.
500Server errorThe turn failed. Retrying is safe; each request creates its own turn.

Embedding the widget

If you want the ready-made chat bubble rather than your own interface, you do not need this API at all. Paste the snippet from your agent's Publish page:

<script
  src="https://chatly.analytos.ai/chatly-widget.js"
  data-chatbot-id="YOUR_AGENT_ID"
  defer
></script>

The widget handles the streaming, the appearance settings and the conversation history for you.

What this API does not do

These two endpoints cover talking to an agent. Creating agents, uploading knowledge, reading conversations and managing connected apps all require a signed-in session and are not part of this public surface — they are done from the dashboard.

An agent only uses connected accounts such as Gmail on behalf of the person who connected them, in the dashboard. A conversation started through this API is an anonymous visitor and never reaches anyone's personal connections.