Amarsia
API Reference

Agent API

Reference the Agent SDK and REST contracts for start, status, history, reconnect, tools, and completion.

Overview

Durable agents use POST /v2/runner/{deployment_id}/conversation for start, continue, and resume. Reconnect reads use the existing GET /v1/runner/conversation/{conversation_id}/messages endpoint.

Use the SDK unless you need direct HTTP control. client.agent and useAgent() manage refresh, capability advertisement, and matching result submission.

Agent SDK

client.agent is the dedicated SDK controller for agent conversations. It uses the REST endpoints documented below without introducing a separate agent resource or agent ID; conversationId is the durable identifier.

MethodReturnsBehavior
start(options)AgentStateStarts an agent turn and opens synchronized state
get(conversationId, options?)AgentStateReads one snapshot without polling
open(conversationId, options?)AgentStateLoads the latest page and keeps state synchronized
loadMoreHistory(options?)AgentStatePrepends the next older agent-history page
loadMoreMessages(options?)AgentStateCompatibility alias for loadMoreHistory
continue(options?)AgentStateStarts another turn on the open conversation
resolveTool(callId, output)AgentStateSubmits results once every call in the pending round is resolved
subscribe(listener)unsubscribe functionNotifies a vanilla JavaScript consumer when open state changes
getState()AgentStateReads the current in-memory controller state
close() / abort()voidStops SDK polling and local work

AgentState

FieldTypeMeaning
conversationIdstring | nullDurable conversation identifier
conversationStatusstring | nullactive or permanently completed
runIdstring | nullCurrent run identifier for observability; never required as input
runStatusAgentRunStatus | nullCurrent execution status
messagesConversationMessage[]Actual user and assistant messages only
historyAgentHistoryItem[]Chronological messages, tools, actions, and client-tool activity
historyPageInfoobject or nullOpaque nextCursor and hasMore
messagesPageInfoobject or nullMessage-only compatibility view derived from history
pendingToolCallsAgentPendingToolCall[]Current unresolved client tools
toolSummaryAgentToolSummary[]Safe tool/action names and statuses
progressAgentProgress[]Safe current-run progress summaries
statusAgentStatusSDK lifecycle status
errorSDK error or nullLatest local/API error

start() accepts both triggerId and conversationId. Use triggerId for trigger-created work and include conversationId only when continuing the conversation already linked to that trigger.

POST /v2/runner/{deployment_id}/conversation

The request body selects one of three operations:

OperationRequired fields
Startcontent or a trigger_id containing content
Continueconversation_id, content
Resolve pending toolsconversation_id, tool_results

Request fields

FieldTypeRequiredDescription
contentMessageContent[]Start without trigger, or continueNon-empty input; a start may omit it when trigger_id supplies stored content
conversation_idUUIDContinue or resumeExisting active conversation
variablesobject of stringsNoInitial conversation variables
metaobjectNoInitial searchable metadata
history_limitintegerNoPrior message pairs supplied to the model; default 5
client_capabilitiesarrayNoTool names or { "name", "input_schema" } objects connected for this request
tool_resultsarrayResumeOne result for every pending call
trigger_idstringNoPrepared trigger for the initial turn

All v2 conversations use durable semantics. Pending client actions remain available for reconnect, and the backend finds the current pending run from conversation_id. When Allow conversation completion is enabled, complete_conversation is available to the model.

Autonomous backend start

Omit client_capabilities when no connected client tools are available:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "content": [{ "type": "text", "text": "Analyze today'\''s support escalations." }],
    "variables": { "TEAM": "enterprise" },
    "meta": { "jobId": "job_8421" }
  }'

A completed turn can return:

{
  "run_id": "5af940ce-8610-42d9-891f-f3f20685fbfa",
  "run_status": "completed",
  "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
  "conversation_status": "active",
  "completed_at": null,
  "name": "Support escalation review",
  "content": "Three escalations require follow-up.",
  "input_tokens": 44,
  "output_tokens": 18,
  "response_time": 1.42
}

run_status: "completed" means this run finished successfully. conversation_status: "active" means another run is allowed. Every v2 run returns a run_id for observability, but clients persist and submit only conversation_id.

run_status is the execution lifecycle:

  • running: the model is executing.
  • waiting_for_client_action: every item in client_tool_calls must be resolved.
  • completed: the run finished successfully.
  • interrupted: accepted client results were saved, but continuation was interrupted.
  • failed: the run failed.
  • expired: a legacy non-agent pending run expired.

conversation_status is separate and is either active or permanently completed.

Continue an active conversation

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
    "content": [{ "type": "text", "text": "Continue." }],
    "client_capabilities": ["ask_user"]
  }'

If the model calls a connected or always tool, the response pauses:

{
  "run_status": "waiting_for_client_action",
  "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
  "conversation_status": "active",
  "completed_at": null,
  "run_id": "d889fae8-a888-45e7-a9bd-ee0cb4baf200",
  "client_tool_calls": [{
    "call_id": "call_1",
    "name": "ask_user",
    "arguments": {
      "questions": [{
        "id": "goal",
        "question": "What is your goal?",
        "input_type": "single_select",
        "options": ["Grow revenue", "Reduce costs"]
      }]
    }
  }],
  "progress": [{
    "type": "client_action_required",
    "call_id": "call_1",
    "name": "ask_user",
    "summary": "What is your goal?"
  }]
}

Resolve ask_user

Resume through the same endpoint with every pending call_id:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
    "client_capabilities": ["ask_user"],
    "tool_results": [{
      "call_id": "call_1",
      "output": {
        "answers": [{ "id": "goal", "value": "Grow revenue" }]
      }
    }]
  }'

Text and single-select answers require a non-empty string. Multi-select answers require an array of strings, and every requested question ID must appear exactly once.

Resolve upload_document

Upload the file first, then send one result for its pending call:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
    "client_capabilities": ["upload_document"],
    "tool_results": [{
      "call_id": "call_upload",
      "output": {
        "content": [{
          "type": "url",
          "mime_type": "application/pdf",
          "file_uri": "https://files.example.com/agreement.pdf"
        }]
      }
    }]
  }'

content must contain at least one non-text file part with mime_type and file_uri, or supported inline data content.

Configure lookup_customer in the dashboard with when_connected availability. Advertise its optional schema for this request:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "content": [{ "type": "text", "text": "Check whether customer cus_123 is active." }],
    "client_capabilities": [{
      "name": "lookup_customer",
      "input_schema": {
        "type": "object",
        "properties": {
          "customerId": { "type": "string" }
        },
        "required": ["customerId"]
      }
    }]
  }'

When the response requests lookup_customer, execute it in your client and resume with its call_id and an object output. The dashboard stores name, description, and availability; it does not require a schema.

Create an emailed always flow

Configure upload_document as always, then create a hosted-agent trigger:

curl https://api.amarsia.com/v1/runner/YOUR_DEPLOYMENT_ID/trigger \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "content": [{ "type": "text", "text": "Collect the signed service agreement." }],
    "variables": { "CUSTOMER_ID": "cus_123" },
    "ui_surface": "agent",
    "ttl_hours": 72
  }'

Use the returned trigger id in:

https://chat.amarsia.com/agent/YOUR_DEPLOYMENT_ID?tid=RETURNED_TRIGGER_ID

The API can also start directly from the trigger without repeating its content or variables:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "trigger_id": "RETURNED_TRIGGER_ID",
    "client_capabilities": ["upload_document"]
  }'

The backend validates the trigger and uses its stored content and variables. Explicit request content or variables override the corresponding trigger values. The hosted route starts or restores the conversation and writes its durable cid into the URL.

GET /v2/runner/{deployment_id}/conversation/{conversation_id}/history

This agent-specific endpoint returns one chronological timeline without changing the existing v1 chatbot history contract:

curl "https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation/CONVERSATION_ID/history?limit=50" \
  -H "x-api-key: YOUR_API_KEY"

items can contain message, tool, action, client_tool, and conversation_completed entries. Each item has a stable id and created_at. Pass next_cursor back as cursor to load older history; treat it as opaque. A null cursor means no older activity remains.

GET /v1/runner/conversation/{conversation_id}/messages

This existing chatbot endpoint remains unchanged. Agent SDKs use the v2 history endpoint instead:

curl "https://api.amarsia.com/v1/runner/conversation/8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b/messages?page=1&page_size=100" \
  -H "x-api-key: YOUR_API_KEY"
Query fieldTypeDefault
pageinteger1
page_sizeinteger20
{
  "items": [{
    "id": 301,
    "role": "user",
    "content": [{ "type": "text", "text": "Collect the onboarding details." }],
    "created_at": "2026-07-11T15:10:00Z"
  }],
  "total": 1,
  "page": 1,
  "page_size": 100,
  "has_more": false,
  "conversation_status": "active",
  "completed_at": null,
  "run_id": "d889fae8-a888-45e7-a9bd-ee0cb4baf200",
  "run_status": "waiting_for_client_action",
  "pending_client_actions": [{
    "call_id": "call_1",
    "name": "ask_user",
    "arguments": {
      "questions": [{
        "id": "goal",
        "question": "What is your goal?",
        "input_type": "text"
      }]
    }
  }],
  "tool_summary": [{
    "name": "lookup_customer",
    "status": "completed"
  }],
  "progress": [{
    "type": "client_action_required",
    "call_id": "call_1",
    "name": "ask_user",
    "summary": "What is your goal?"
  }]
}

items contains actual stored messages only. Pending client tools, tool usage summaries, and safe progress are separate fields; linked server actions remain action logs.

Reconnect directly

  1. Read every message page you need to render.
  2. Stop writes if conversation_status is completed.
  3. Render items, progress, and tool_summary separately.
  4. If pending_client_actions is non-empty, collect an output for every call and submit it with conversation_id.
  5. Refresh after 409 because another client may have accepted the results.
  6. If run_status is interrupted, start a new agent turn with "Continue."; do not replay accepted results.

Two browsers can read the same pending call. The first accepted matching result set wins, an identical retry is idempotent, and different outputs for the same call IDs conflict.

Completion

When Allow conversation completion is enabled, the model can call complete_conversation. A request can ask the assistant to close resolved work:

curl https://api.amarsia.com/v2/runner/YOUR_DEPLOYMENT_ID/conversation \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "conversation_id": "8bd6d8ca-fc71-4d46-858b-e50b4a9bf83b",
    "content": [{ "type": "text", "text": "Everything is resolved. Close this case." }]
  }'

The model requests completion, but the backend applies it only after the round ends, with no pending client action, and only when complete_conversation was the final executed server tool. Premature requests are logged as not_completed and leave the conversation active. Check conversation_status and completed_at in the response or messages read. Completion is permanent, does not delete stored data, and later start, continue, or resume attempts return 409 conversation_completed.

Errors and concurrency

CodeStatusMeaning
missing_tool_results400One or more pending call IDs have no result
unknown_call_id400A result references a non-pending call
invalid_tool_result400A built-in or custom output is invalid
client_action_required409A new turn was attempted while input is pending
run_in_progress409A new turn was attempted while a run is active
action_result_conflict409Different outputs were already accepted for these call IDs
conversation_completed409The conversation is permanently completed
run_expired409A legacy non-agent pending run expired