Agents

Chat with AI agents via REST. For SDK helpers (sendMessage, run, streaming), see the Agent SDK.

Most integrations use POST /agents/run — it creates a chat when needed, sends the user message, and returns assistant output. Use the tool endpoints below for client tools, widgets, and human-in-the-loop (HIL) approval.


POST /agents/run

Send a message to a template or ad-hoc agent. Creates a new chat when chat_id is omitted.

Request

FieldTypeRequiredDescription
chat_idstringNoExisting chat ID (omit to start a new chat)
agentstringNoTemplate agent ref (namespace/name@version)
agent_configobjectNoAd-hoc agent config (tools, system prompt, core app)
agent_namestringNoDisplay name for ad-hoc chats
contextobjectNoPer-chat context for call-tool URL templates (only when starting a new chat)
inputobjectYesMessage payload (see below)
streambooleanNoIf true, response is SSE instead of JSON

input fields:

FieldTypeDescription
textstringUser message text
attachmentsarrayFile refs (uri, filename, content_type) from Files API
rolestringUsually "user"

Template agent (new chat):

json
1{2  "agent": "myteam/support-agent@latest",3  "context": {4    "project_id": "proj_456"5  },6  "input": {7    "text": "Summarize open tickets"8  }9}

Continue chat:

json
1{2  "chat_id": "chat_abc123",3  "input": {4    "text": "What about priority ones?"5  }6}

Response

With X-API-Version: 2 (recommended; sent automatically by the SDKs and belt/infsh CLIs), the response body is the DTO directly:

json
1{2  "user_message": { "id": "msg_...", "chat_id": "chat_abc123", "role": "user", "content": [...] },3  "assistant_message": { "id": "msg_...", "chat_id": "chat_abc123", "role": "assistant", "content": [...], "tool_invocations": [...] }4}

Without the version header, the same payload is nested under data in a { "success": true, "data": { ... } } wrapper. See REST overview — API version.

Set stream: true to receive message updates over SSE. See Stream chat updates.


Send message (alternate)

POST /agents/message or POST /agents/messages

Same request body as Run agent, using agent_id / agent_version_id instead of agent when referencing a stored template:

json
1{2  "agent_id": "agent_abc123",3  "agent_version_id": "ver_xyz789",4  "input": { "text": "Hello" }5}

List chats

GET /chats or POST /chats/list

Cursor-paginated list of chats. POST /chats/list accepts a JSON body with limit, cursor, direction, and filters (for example status in busy, awaiting_input).


Get chat

GET /chats/:id

Returns the chat, message history, and tool invocations.

Response

FieldTypeDescription
idstringChat ID
statusstringbusy, idle, awaiting_input, or completed
chat_messagesarrayMessages with content, role, and optional tool_invocations
outputobjectStructured result from the agent's finish tool (when set)
contextobjectPer-chat context values
json
1{2  "id": "chat_abc123",3  "status": "awaiting_input",4  "chat_messages": [5    {6      "role": "assistant",7      "tool_invocations": [8        {9          "id": "ti_abc123",10          "status": "awaiting_approval",11          "function": { "name": "delete_file", "arguments": { "path": "/tmp/old.txt" } }12        }13      ]14    }15  ]16}

output is populated when the agent calls the internal finish tool. See Structured Output.

For live updates, use Stream chat messages or GET /chats/:id/status for status-only polling.


Get chat trace

GET /chats/:id/trace

Returns the execution graph for an agent chat: nodes (assistant turns, tool invocations, sync barriers), edges (dependencies), and step counts by status. Requires the conversations:read scope (same as other chat endpoints).

Use this to debug agent runs programmatically — see which tools ran, how long each step took, and where failures occurred. The workspace shows the same trace in the chat UI.

Response

FieldTypeDescription
graph_idstringGraph identifier (same as the chat ID)
nodesarrayExecution steps (type, label, status, resource_id, started_at, completed_at, duration_ms, …)
edgesarrayDependencies between nodes (from_node, to_node, type)
total_stepsnumberTotal nodes in the graph
completed_stepsnumberSteps that finished successfully
running_stepsnumberSteps still in progress
failed_stepsnumberSteps that failed

Example:

bash
1curl https://api.inference.sh/chats/chat_abc123/trace \2  -H "Authorization: Bearer inf_your_key" \3  -H "X-API-Version: 2"

JavaScript SDK: client.chats.getTrace('chat_abc123').

Observability · Stream chat updates


Chat status values

StatusMeaning
busyAgent is working — LLM generation, or automated tool execution (apps, sub-agents, hooks, client tools, MCP)
idleAgent finished; chat can accept new messages
awaiting_inputA human must act on this chat: HIL tool approval or an interactive widget
completedTerminal state (archived chat)

Client tools and hooks keep the chat in busy while they execute. Use chat.status === "awaiting_input" when you need a human on the conversation; use tool invocation status for per-tool progress.


Stop chat

POST /chats/:id/stop

Stop the current agent run and cancel pending tool invocations.

JavaScript SDK: client.chats.stop('chat_abc123') — or agent.stopChat() when using client.agent().


Tool invocations

Tool calls on assistant messages expose tool_invocations. Each invocation has an id used by the endpoints below.

Tool invocation status

StatusMeaning
pendingQueued
in_progressExecuting — apps, sub-agents, client tools, hooks, MCP
awaiting_inputInteractive widget or form needs human input
awaiting_approvalHIL approval needed before execution
completedDone
failedError
cancelledCancelled

Submit tool result

POST /tools/:toolInvocationId

Submit a result for client tools (in_progress) or interactive widgets (awaiting_input).

Request

json
1{2  "result": "{\"temperature\": 72}"3}

For widget actions, JSON-serialize { "action": {...}, "form_data": {...} } into result, or use the deprecated POST /tools/:id/widget endpoint.

The JavaScript and Python SDKs call this via submitToolResult / submit_tool_result. See Client Tools.


Approve tool (HIL)

POST /tools/:toolInvocationId/invoke

Approve a tool with status: awaiting_approval and execute it. Returns 400 invalid_state if the invocation is not awaiting approval.

bash
1curl -X POST https://api.inference.sh/tools/ti_abc123/invoke \2  -H "Authorization: Bearer inf_your_key"

Approval settings · Human-in-the-loop


Reject tool (HIL)

POST /tools/:toolInvocationId/reject

Reject a pending approval. The agent continues with the rejection reason.

Request

json
1{2  "reason": "Not authorized to delete files"3}

reason is optional.


Always allow tool

POST /chats/:chatId/tools/:toolInvocationId/always-allow

Approve the current invocation and add the tool to this chat's always-allowed list.

Request

json
1{2  "tool_name": "delete_file"3}

Human-in-the-loop workflow

  1. Run an agent with tools marked require_approval (see Approval settings).
  2. Poll or stream the chat until status is awaiting_input.
  3. In GET /chats/:id, find invocations with status: awaiting_approval.
  4. Call POST /tools/:id/invoke to approve or POST /tools/:id/reject to reject.
  5. Poll or stream again until the agent reaches idle or completed.

List chats with status in busy or awaiting_input to find conversations needing action. The belt CLI wraps this flow with belt chat pending, belt chat approve, and belt chat reject — see CLI Setup.


cURL example

bash
1# Start or continue a chat2curl -X POST https://api.inference.sh/agents/run \3  -H "Authorization: Bearer inf_your_key" \4  -H "Content-Type: application/json" \5  -d '{6    "agent": "myteam/support-agent@latest",7    "input": { "text": "Hello!" }8  }'910# Get chat (includes tool invocations)11curl https://api.inference.sh/chats/chat_abc123 \12  -H "Authorization: Bearer inf_your_key"1314# Approve a tool awaiting HIL15curl -X POST https://api.inference.sh/tools/ti_abc123/invoke \16  -H "Authorization: Bearer inf_your_key"

Messaging channel webhooks

Connect external chat platforms so users can talk to an agent where they already work. Inbound platform events create agent messages; agent replies are delivered back through the same channel.

Receive events

POST /agents/{id}/channel/{provider}

ParameterDescription
idAgent ID
providerIntegration provider slug (currently slack)

Legacy route (Slack only): POST /agents/{id}/slack — same behavior as provider=slack.

No API key is required. The platform verifies the request (for Slack, using your app's Signing Secret from the Slack integration). URL verification challenges (for example Slack url_verification) are answered automatically.

Example (Slack event subscription Request URL):

code
1https://api.inference.sh/agents/agent_abc123/channel/slack

On a valid inbound message, the API acknowledges immediately (200 with {"status":"ok"}) and processes the message asynchronously. Thread history is fetched when the channel supports it, so the agent has prior context.

Supported providers are registered per deployment; check integration guides for availability. See Chatting with Agents for the workspace workflow.


Get A2A agent card

GET /agents/{id}/card
GET /agents/{namespace}/{name}/card

Returns an Agent2Agent (A2A) protocol agent card for agent discovery and marketplace listings (for example GCP AI Agents Producer Portal). Requires agents:read.

The response is raw A2A JSON — not wrapped in the usual { "success": true, "data": … } envelope. Resolve the agent by ID or by namespace/name ref.

bash
1curl https://api.inference.sh/agents/myteam/support-agent/card \2  -H "Authorization: Bearer inf_your_key" \3  -H "X-API-Version: 2"

Example response:

json
1{2  "name": "myteam/support-agent",3  "description": "Customer support assistant",4  "version": "1.0.0",5  "url": "https://app.inference.sh/agents/myteam/support-agent",6  "provider": { "name": "inference.sh", "url": "https://inference.sh" },7  "capabilities": { "streaming": true, "pushNotifications": false },8  "defaultInputModes": ["text/plain"],9  "defaultOutputModes": ["text/plain", "application/json"],10  "skills": [11    { "id": "search-tickets", "name": "Search tickets", "tags": ["app"] }12  ],13  "securitySchemes": [{ "scheme": "bearer" }]14}

Skills are derived from the agent's current version tools (apps, sub-agents, MCP servers, HTTP hooks) and attached knowledge skills. In the workspace, open an agent and use a2a card on the detail header to copy this JSON to the clipboard.

JavaScript SDK (@inferencesh/sdk ≥ v0.6.12): client.agents.getA2ACard('agent_abc123') — returns the same raw card object. See JavaScript SDK — Agent SDK.


Create or update agent template

POST /agents

Creates a saved agent template, or adds a new version when an agent with the same name already exists in your team's namespace. Requires the agents:write scope.

This mirrors app deploy semantics: the namespace is assigned server-side from your team username, so redeploying only requires the agent name and a version payload. You do not need to look up the agent ID first, and the namespace field in the request is optional.

FieldTypeRequiredDescription
namestringYesAgent name (unique per team namespace)
namespacestringNoOptional — server uses your team username
idstringNoAgent ID — include to create a new version of a known agent (alternative to name-based upsert)
versionobjectNoVersion config (system_prompt, core_app, tools, skills, context, output_schema, …)

When name matches an existing agent, the API creates a new version and sets it as current (same outcome as POST /agents/{id} with a version payload). Omitting visibility on redeploy preserves the existing visibility setting.

Example — first deploy:

bash
1curl -X POST https://api.inference.sh/agents \2  -H "Authorization: Bearer inf_your_key" \3  -H "Content-Type: application/json" \4  -H "X-API-Version: 2" \5  -d '{6    "name": "support-agent",7    "version": {8      "description": "Customer support assistant",9      "system_prompt": "You help users with billing questions.",10      "core_app": { "ref": "openrouter/claude-sonnet-46" }11    }12  }'

Example — redeploy same name (creates new version):

Send the same request shape with updated version fields — no agent ID lookup required.

To update by ID instead (for example when you already have agent_abc123), use POST /agents/{id} with a version object. To change visibility or store images without a new version, use POST /agents/{id}/visibility or include only agent-level fields in POST /agents/{id}.

CLI: belt agent deploy <path> and belt agent create both use this endpoint. See CLI setup — Agents.


Delete agent template

DELETE /agents/{id}

Permanently deletes a saved agent template (workspace definition). Requires the agents:write scope. This does not delete chat history from past runs.

bash
1curl -X DELETE https://api.inference.sh/agents/agent_abc123 \2  -H "Authorization: Bearer inf_your_key"

CLI equivalent: belt agent delete <ref> (accepts agent ID or namespace/name). See CLI setup — Agents.


we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.