tools/list endpoint exposed to anonymous callers — the chatbot is the agent.
Endpoint
Declaring you are an agent
Send theX-Agent-Model header so the chatbot knows it’s talking to another agent (not a human). It tags the conversation, switches the tool channel to api, and triggers the structured JSON envelope response automatically.
[AGENT:model-name] — the chatbot strips it out and treats the rest as the question.
Response shape (agent-aware)
WhenX-Agent-Model is present and stream is not explicitly set, you get a single JSON response. No SSE parsing.
| Field | Type | Description |
|---|---|---|
message | string | Prose reply from the chatbot |
sessionId | string | Echoed back. Reuse it on the next call to keep context |
conversationId | string | Canonical conversation handle (DB id) |
messageCount | number | Total messages in this conversation |
visitorType | "agent" | "human" | Resolved from X-Agent-Model header / [AGENT:] prefix |
agentModel | string | undefined | Echo of what the caller declared (truncated to 100 chars). Declarative — not verified |
toolExecutions | array | [] | Tools the chatbot invoked while building the reply. Sanitized: no raw inputs |
contactSubmitted | boolean | true if a SUBMIT_FORM tool was successfully called |
toolResults | object | undefined | Map of toolName → success for each tool invoked |
status | "escalated" | undefined | Set when the chatbot escalated to a human |
llmSource | "managed" | "passthrough" | "stored" | "webhook" | Where the LLM key came from |
llmProvider | string | "anthropic", "openai", "mistral", … |
llmModel | string | undefined | The exact model that generated the reply (e.g. claude-haiku-4-5). Absent for webhook mode |
X-AI-Generated: true (AI Act Art. 50 transparency).
Tool executions, not tool calls
toolExecutions[] reports what the chatbot did internally — not actions you can invoke. The chatbot decides which tools to use based on the question.
If the chatbot collects a contact via SUBMIT_FORM, books a meeting via BOOK_MEETING, or charges via COLLECT_PAYMENT, the agent caller sees it in toolExecutions[] with structured data. Useful for:
- attribution (the agent caller wrote the lead, not a random visitor)
- follow-up logic (e.g., the agent caller polls a CRM after seeing
submission.created) - debugging (which tool ran, did it succeed, what did it return)
Multi-turn conversations
Reuse the returnedsessionId (or conversationId):
sessionId.
Streaming (opt-in for agents)
Streaming is the default for browsers but opt-in for agents. Setstream: true to receive SSE chunks, ending with a done event that carries the same envelope fields.
Discovery before talking
Before sending the first message, an agent can introspect the tenant:segment to target.
Rate limits
| Window | Per-IP limit |
|---|---|
| 1 minute | 20 messages |
| 1 hour | 200 messages |
Retry-After.
Errors
| HTTP | Body | Meaning |
|---|---|---|
| 400 | { "error": "message and sessionId are required" } | Missing required field or message > 15000 chars |
| 403 | { "error": "Origin not allowed" } | Tenant restricts allowed origins |
| 403 | { "error": "Invalid or missing widget key" } | Tenant requires a widget key |
| 404 | { "error": "Tenant not found" } | Bad slug |
| 402 | { "error": "Plan not activated", "code": "NOT_ACTIVATED" } | Tenant on a plan without widget capability |
| 429 | { "error": "Conversation limit reached", "code": "LIMIT_REACHED", "nextResetAt": "..." } | Monthly conversation cap hit |
Integration examples
Python — agent-to-agent
LangChain Tool
Next steps
Agent-Ready
Full agent-readiness layers (.well-known files, MCP, JSON-LD)
Discovery
Introspect a tenant before chatting