AI

AI agents

Run an AI agent inside a conversation. The agent reads the customer's messages, retrieves knowledge you've approved, calls tools you define to act in your systems, and either replies or hands off to a person — all while you just exchange messages over the API. The same agent works across SMS, chat, email, and voice, and every run is logged so you can see exactly what it read, decided, and did.

How a turn works

Each time a customer message arrives, the agent performs a run. A run is a short, auditable loop:

  1. Understand — interpret the message in the context of the full conversation and any customer details you've attached.
  2. Retrieve — pull relevant passages from the agent's knowledge sources when an answer needs grounding.
  3. Act — call one or more tools to look things up or make changes in your systems. Tool calls can chain: the result of one can inform the next.
  4. Respond or hand off — produce a grounded reply, or, when a guardrail or low confidence is hit, return a handoff to a human with a summary.

You never orchestrate these steps yourself. You post a message and read back a completed run; AtomMatrix runs the loop, enforces the guardrails, and delivers the reply on the conversation's channel.

Concepts & object IDs

ObjectPrefixDescription
Agentagt_A configured assistant: instructions, knowledge sources, tools, guardrails, and handoff rules. You build agents in the console and reference them by agent_id.
Conversationcnv_An ongoing thread with one customer, spanning one or more channels.
Messagemsg_A single turn, authored by the customer, the agent, or a human.
Runrun_Everything the agent did in response to a customer message — retrieval, tool calls, the reply, or a handoff.
ToolA named action the agent can take by calling an HTTPS endpoint you own.

The agent object

Agents are authored and versioned in the console; the API exposes them read-only so your code can discover which agents exist and what they're capable of before starting a conversation.

GET/v1/agents
GET/v1/agents/{id}
{
  "id": "agt_support_en",
  "name": "Support — English",
  "status": "live",
  "channels": ["sms", "chat", "email"],
  "locales": ["en", "es", "fr"],
  "knowledge_sources": ["kb_help_center", "kb_shipping_policy"],
  "tools": ["get_order", "cancel_order", "issue_refund"],
  "guardrails": {
    "requires_approval": ["issue_refund"],
    "restricted_topics": ["legal_advice"]
  },
  "handoff": { "default_queue": "support", "on_low_confidence": true },
  "version": 7,
  "updated_at": "2026-06-30T12:04:11Z"
}
An agent must be live to start a conversation. A draft agent returns 422 agent_not_live. Publish from the console when you're ready.

Create a conversation

POST/v1/conversations
ParameterDescription
agent_id stringREQUIREDThe agent to run. Must be live.
channel stringOPTIONALsms, chat, email, or voice. Determines how replies are delivered. Defaults to chat (reply returned in the API response only).
customer objectOPTIONALKnown details the agent can use: id, name, phone, email, locale.
context objectOPTIONALStructured facts to seed the run — e.g. { "plan": "pro", "account_status": "active" }. The agent may use these without a tool call.
tags arrayOPTIONALLabels for routing and analytics, e.g. ["billing", "vip"].
metadata objectOPTIONALYour own key–value context, echoed back on every object.
curl https://api.atommatrix.ai/v1/conversations \
  -H "Authorization: Bearer sk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_support_en",
    "channel": "chat",
    "customer": { "id": "cus_8842", "name": "Jordan", "locale": "en" },
    "context": { "plan": "pro", "account_status": "active" },
    "tags": ["support"]
  }'

Retrieve & list conversations

GET/v1/conversations/{id}
GET/v1/conversations

List supports filtering by agent_id, status (active, handed_off, closed), channel, tag, and a created range, plus cursor pagination.

GET /v1/conversations?agent_id=agt_support_en&status=handed_off&limit=20

Send a message & get a run

POST/v1/conversations/{id}/messages

Post the customer's message. The response includes the agent's run — the reply it generated and any tools it called. If the conversation is on a live channel like SMS or voice, the reply is also delivered on that channel automatically.

ParameterDescription
role stringREQUIREDcustomer for an inbound message. Use human to inject an agent-desk reply into the transcript without triggering a run.
content stringREQUIREDThe message text. For inbound media, use attachments.
attachments arrayOPTIONALURLs of images or documents the agent should consider (e.g. a photo of a damaged item).
trigger_run booleanOPTIONALDefaults to true. Set false to append a message without asking the agent to respond.
curl https://api.atommatrix.ai/v1/conversations/cnv_01HN9V.../messages \
  -H "Authorization: Bearer sk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "role": "customer", "content": "Where is my order 10842?" }'

Response

{
  "id": "msg_01HN9W...",
  "role": "customer",
  "content": "Where is my order 10842?",
  "run": {
    "id": "run_01HN9W...",
    "status": "completed",
    "confidence": 0.93,
    "retrieval": [
      { "source": "kb_shipping_policy", "title": "Delivery windows", "score": 0.81 }
    ],
    "tool_calls": [
      { "tool": "get_order", "arguments": { "order_id": "10842" }, "result_status": "ok", "latency_ms": 240 }
    ],
    "reply": {
      "role": "agent",
      "content": "Your order 10842 shipped yesterday and is out for delivery today. Want the tracking link?"
    },
    "handoff": null,
    "usage": { "input_tokens": 812, "output_tokens": 96 }
  }
}

List messages

GET/v1/conversations/{id}/messages

Return the full transcript in order, including customer, agent, and human turns. Use this to render a live chat panel or rebuild context after a handoff. Results are cursor-paginated, oldest first by default; pass order=desc for newest first.

The run object

A run is created for you whenever a message triggers the agent, but it's also a first-class resource you can retrieve — useful for auditing, for polling an asynchronous run, or for showing "the agent is working" states in your UI.

GET/v1/runs/{id}
FieldDescription
status stringSee the lifecycle below.
confidence number0–1 estimate of how well-grounded the reply is. Low values can trigger handoff.
retrieval arrayKnowledge passages the agent used, with source and relevance score. Powers citations.
tool_calls arrayEach tool the agent invoked, its arguments, result_status, and latency.
reply objectThe agent's message, or null if the run ended in a handoff.
handoff objectPresent when the run escalated to a human.
usage objectToken counts for the run, for cost attribution.

Run status lifecycle

StatusMeaning
queuedAccepted, not yet started.
in_progressThe agent is understanding, retrieving, or calling tools.
requires_actionWaiting on an asynchronous tool (see async tools) or a human approval.
completedFinished with a reply and/or a handoff.
failedAn unrecoverable error occurred; inspect error. No customer reply was sent.
expiredA required action wasn't fulfilled in time and the run was abandoned.

Streaming a run

For chat UIs that show the reply as it's written, open the run as a stream of server-sent events instead of waiting for the full response. You'll receive incremental events as the agent retrieves, calls tools, and composes text.

POST/v1/conversations/{id}/messages?stream=true
event: run.started
data: { "run_id": "run_01HN9W..." }

event: tool.called
data: { "tool": "get_order", "arguments": { "order_id": "10842" } }

event: reply.delta
data: { "text": "Your order 10842 shipped " }

event: reply.delta
data: { "text": "yesterday and is out for delivery today." }

event: run.completed
data: { "run_id": "run_01HN9W...", "status": "completed" }

Tools

Tools are how an agent does more than talk. Each tool has a name, a description the agent uses to decide when to call it, a JSON Schema for its arguments, and an HTTPS endpoint you own. When the agent chooses a tool, AtomMatrix validates the arguments against your schema, calls your endpoint, waits for your JSON response, and lets the agent continue with the result.

Defining a tool

Tools are configured on the agent in the console. A definition looks like this:

{
  "name": "get_order",
  "description": "Look up the status and shipping details of an order by its ID.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": { "type": "string", "description": "The customer's order number." }
    },
    "required": ["order_id"]
  },
  "endpoint": "https://api.yourco.com/tools/get_order",
  "timeout_ms": 5000
}

The call contract

AtomMatrix signs every tool request with the same HMAC signature scheme used for webhooks, so you can verify the call really came from us. Respond with 200 and a JSON body; the agent receives your body as the tool result.

// AtomMatrix calls your tool endpoint:
POST https://api.yourco.com/tools/get_order
Atom-Signature: t=1751894400,v1=5f1e...
{
  "tool": "get_order",
  "arguments": { "order_id": "10842" },
  "conversation_id": "cnv_01HN9V...",
  "run_id": "run_01HN9W..."
}

// Your endpoint responds:
{ "status": "shipped", "eta": "2026-07-07", "tracking": "1Z999AA10123456784" }

Returning an error

If the action can't be completed, return a non-2xx status or an error object. The agent sees the failure and adapts — it might apologize, try a different path, or hand off — rather than inventing a result.

// 404 — the agent will tell the customer the order wasn't found
{ "error": { "code": "not_found", "message": "No order matches 10842." } }
Timeouts & retries. If your endpoint doesn't respond within timeout_ms, the call is marked timed_out and the agent proceeds without it. We retry idempotent tool calls once on network errors; make your handlers idempotent using the run_id.

Long-running (async) tools

For actions that can't finish in a few seconds — a manual review, a batch job — respond with 202 and { "status": "pending" }. The run moves to requires_action. Submit the result later and the agent resumes:

POST/v1/runs/{id}/tool_results
{ "tool_call_id": "call_01HN9X...", "result": { "approved": true } }
Guardrails apply to actions, not just words. Which tools an agent may call, and when a human must approve, are set on the agent. A refund tool can require approval above a threshold while an order-lookup runs freely. See guardrails and Security & governance.

Knowledge & retrieval

An agent answers from the knowledge sources attached to it — your help center, policies, product data, or documents you've indexed — not from a generic guess. When retrieval is used, the passages appear in the run's retrieval array with a relevance score, so you can surface citations and audit where an answer came from.

"retrieval": [
  {
    "source": "kb_shipping_policy",
    "title": "Delivery windows",
    "snippet": "Standard orders ship within one business day...",
    "score": 0.81
  }
]

If nothing relevant is found and the agent isn't confident, it says so or hands off rather than fabricating an answer. You manage sources and re-indexing in the console; the agent always retrieves from the latest published version.

Guardrails

Guardrails are limits set on the agent that the platform enforces on every run — you don't have to police them in your own code:

When a guardrail stops an action, the run records why in the handoff or a guardrail note, so nothing happens silently.

Human handoff

When the agent hits a guardrail, low confidence, or an explicit customer request, the run returns a handoff object instead of (or alongside) a reply, and a conversation.handoff webhook fires so your agent desk can pick it up with the full transcript and a written summary attached.

"handoff": {
  "reason": "requires_approval",
  "queue": "billing",
  "summary": "Customer requests a $240 refund on order 10842 (shipped, undamaged).",
  "suggested_reply": "I can request that refund for you — a specialist will confirm shortly."
}

A human replies by posting a message with role: "human". To return control to the agent once the case is resolved, close the handoff:

POST/v1/conversations/{id}/resume
{ "note": "Refund approved and processed. Agent may resume." }

Channel behavior

ChannelHow replies are delivered
chatReturned in the API response (and stream). You render them in your app.
smsSent automatically over Messaging to the customer's number; long replies are segmented.
emailSent over Email, threaded on the conversation's subject.
voiceSpoken by an AI Voice session; replies are synthesized and tool calls run mid-call.

Because context lives on the conversation, a thread can start on SMS and continue by email without the customer repeating themselves.

Events

Subscribe via Webhooks to drive your own UI and systems:

EventFires when
conversation.messageA new inbound, agent, or human message is added.
run.completedA run finishes — inspect the reply, tool calls, and usage.
run.requires_actionA run is waiting on an async tool result or an approval.
conversation.handoffThe agent escalated to a human queue.
conversation.closedThe conversation was resolved and closed.

Common errors

CodeMeaning
agent_not_live 422The referenced agent is a draft. Publish it first.
channel_not_supported 422The agent isn't configured for the requested channel.
conversation_closed 409You posted to a closed conversation. Start a new one.
tool_result_expired 409An async tool result arrived after the run expired.

See Errors & limits for the shared error object, status codes, and rate limits.