Test Console & Turn Log
Beta
Conversational Agents are in Beta and available on Professional, Scale and Enterprise.
Test console
POST /api/v1/automation/agents/{agent_id}/test — scope automation:update.
Runs one real turn with your current configuration, skills and knowledge:
- Nothing is sent to any contact and nothing is billed.
creditsshows what a live turn would cost. - It works while the agent is inactive.
- The
handoffandcomplete_tasktools and goal completion actions are simulated: they are reported, not carried out. - The turn is written to the turn log with
surface: "test". - Limited to 20 turns per minute and 200 per hour per workspace.
Request
{
"message": "I want to return order 10042, the boots are too small",
"history": [
{"role": "user", "text": "Hi"},
{"role": "agent", "text": "Hi! How can I help?"}
],
"state": {},
"channel_type": "whatsapp",
"skill_slug": null,
"task": null
}
| Field | Notes |
|---|---|
message | Required. 1-4,000 characters. |
history | Earlier turns, oldest first. Up to 50 items, role user or agent, text max 4,000 characters. |
state | The state returned by the previous test turn. Max 8 KB. Send it back unchanged to continue a conversation, including goals in progress. |
channel_type | Optional, e.g. whatsapp, live_chat, email. Max 32 characters. Lets you test channel-specific behaviour. |
skill_slug | Optional. Start with this skill loaded, as a Flow would. |
task | Optional. Simulate a Flow task: {"goal_prompt": "…", "input_variables": {…}, "output_schema": {…}, "skill_slug": "…"}. Max 16 KB; goal_prompt max 4,000 characters. See Agents in Flows. |
Response
{
"replies": [
{"text": "Thanks! I've noted order 10042. You can print your free return label at https://www.example.com/returns", "provenance": [{"type": "kb", "title": "Returns policy", "url": "https://www.example.com/returns"}], "buttons": null}
],
"outcome": "answered",
"outputs": null,
"handoff": null,
"model": "…",
"router": {"skills": ["order-return"], "language": "en", "needs_kb": true, "needs_web": false, "latency_ms": 380, "model": "…"},
"skills_loaded": [
{"slug": "shop-basics", "version": 2, "source": "always"},
{"slug": "order-return", "version": 3, "source": "router"}
],
"tool_calls": [
{"name": "search_knowledge", "status": "ok", "credits": 1, "latency_ms": 640, "results": 3}
],
"link_fixes": [
{"original": "https://www.exmaple.com/return", "action": "repaired", "replacement": "https://www.example.com/returns"}
],
"credits": {"messages": 1, "credits_per_message": 1, "tools": 1, "waived": 0, "by_charge": {"kb_lookup": 1, "bot_message": 1}, "billed": false, "would_bill": 2},
"engine_trace": [{"step": "router", "…": "…"}],
"state": {},
"turn_id": "…"
}
| Field | Notes |
|---|---|
replies | The messages the agent would send: text, provenance (kb, faq or web sources) and buttons. |
outcome | See Turn outcomes. |
outputs | Task outputs when the agent completed a Flow task. |
handoff | {summary, reason, tag_id} when the agent handed over. |
model | The model that answered. |
router | The skill classifier's decision: skills it preloaded, detected language, needs_kb, needs_web, latency_ms, model. null when it did not run (for example when no model_selected skills exist). |
skills_loaded | Each loaded skill with its version and source: always (always-on, Flow skill or active goal), router (preloaded by the classifier) or tool (loaded by the agent with load_skill). |
tool_calls | Each tool call: name, status (ok, empty = searched but found nothing, error), credits, latency_ms, results (number of results for search_knowledge and web_search, otherwise null). |
link_fixes | Links changed by the link check: original, action (repaired or removed) and replacement. |
credits | messages, credits_per_message (1, or 2 when the advanced model wrote the reply), tools, waived (messages that would not be billed), by_charge (credits per charge type), billed (always false here) and would_bill (the total a live turn would cost). |
engine_trace | Step-by-step debugging detail. Its content is not a stable contract; use it for troubleshooting only. For skill goals it contains a goal_actions_dry_run step with would_execute. |
state | Conversation state after the turn. Send it back with the next test turn. |
turn_id | The id of the turn log entry. |
Hand-off rules in the test console
Keyword, max_turns and max_consecutive_fallbacks rules apply in the test console too. The turn number is taken from history, and the fallback counter travels in state, so keep sending state back.
Errors
| Status | When |
|---|---|
404 | "Agent not found" |
422 | Invalid request (lengths, sizes, slug format) |
429 | {"detail": {"error": "rate_limit_exceeded", "message": "…", "retry_after": 42}} with a Retry-After header |
Turn log
GET /api/v1/automation/agents/{agent_id}/turns — scope automation:read.
The audit log of every turn the agent ran, newest first, including test console turns.
| Parameter | Notes |
|---|---|
conversation_id | Optional. Only turns of this conversation. |
page, page_size | page_size default 50, max 100 |
{
"items": [
{
"id": "…",
"agent_id": "…",
"bot_id": "…",
"conversation_id": "…",
"session_id": "…",
"flow_run_id": null,
"inbound_message_id": "…",
"surface": "inbox",
"model": "…",
"outcome": "answered",
"router_result": {"skills": ["order-return"], "language": "en", "needs_kb": true, "needs_web": false, "latency_ms": 380},
"skills_loaded": [{"slug": "order-return", "version": 3, "via": "router"}],
"tool_calls": [{"name": "search_knowledge", "status": "ok", "latency_ms": 640, "result_count": 3, "billed_credits": 1}],
"provenance": [{"type": "kb", "title": "Returns policy", "url": "https://www.example.com/returns"}],
"reply_message_ids": ["…"],
"handoff_reason": null,
"error": null,
"latency_ms": 2140,
"tokens_in": 5210,
"tokens_out": 96,
"credits_billed": 2,
"created_at": "2026-10-05T09:12:44Z"
}
],
"pagination": {…}
}
| Field | Notes |
|---|---|
surface | inbox (messaging channels), live_chat, email, flow or test |
skills_loaded[].via | always_on, router, load_skill or flow |
handoff_reason | See Hand-off reasons |
error | A short error label when outcome is error |
credits_billed | AI credits billed for this turn. Always 0 for test turns. |
The raw model conversation is never returned. Tool arguments are stored redacted.