camelAI Documentation

API Reference

camelRun REST API reference

Create camelRun agents, send prompts, poll runs and read events over HTTP: the REST API's endpoints and conventions.

View as Markdown · Docs index for coding agents

The REST API is served under https://run.camelai.com/v1. The full specification is /v1/openapi.json (OpenAPI 3). Every request sends Authorization: Bearer <API key>; see Authentication.

The SDKs wrap all of this, including tool calls over the agent's own connection, which REST alone can't serve. Use REST for languages without an SDK, and for scripts.

Create an agent

bash
curl https://run.camelai.com/v1/agents \
  -H "Authorization: Bearer $CAMELAI_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: support-triage" \
  -d '{"model": "anthropic/claude-sonnet-5-5", "systemPrompt": "Be concise.", "builtins": ["web_search"]}'
json
{"id": "client_...", "token": "...", "expiresAt": null}

The Idempotency-Key is the agent's key: the same key returns the same agent, brought to the configuration you send. The body takes name, type, model, systemPrompt, systemPromptAppend, thinkingLevel, maxOutputTokens, temperature, dataCollection, builtins, delegate, mcpServers, definition, workspaceId, subject, context, keyScope, spendLimit, bucket, runLimits, modelHeaders, mounts, remount, fileTools, codeMode, ttlSeconds, idleTtlSeconds, prompt (a first prompt, run once the agent is made), and initialMessages or importMessages (a conversation in Anthropic's or OpenAI's format). An unknown field is refused with a 400.

It also takes prompt, a first message with the same body as POST /v1/agents/{id}/prompt. The answer then carries prompt: the request to poll, or {error} if it was refused. The agent is made either way.

Send a message and get the result

bash
curl https://run.camelai.com/v1/agents/$AGENT/prompt \
  -H "Authorization: Bearer $CAMELAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Which tickets look urgent?", "requestId": "msg-8812", "from": {"id": "u_42", "name": "Ada"}}'

The prompt answers 202 with the request record. requestId is optional; it makes the prompt idempotent, so sending the same one again returns the same run. Other fields are files, metadata, whileRunning (queue or steer), spendLimit, runLimits, bucket, allowDisconnected and output ({schema}, for structured output).

Read the request with ?wait=25: it answers as soon as the run ends, or after 25 seconds with state: "running", and you ask again:

bash
curl "https://run.camelai.com/v1/agents/$AGENT/requests/msg-8812?wait=25" \
  -H "Authorization: Bearer $CAMELAI_API_KEY"
json
{"id": "msg-8812", "method": "prompt", "state": "completed",
 "outcome": {"result": {"reply": "Tickets 4411 and 4417...", "replyIndex": 5, "messages": 6,
                        "error": null, "files": [],
                        "toolCalls": [{"tool": "helpdesk__list_tickets", "toolCallId": "call_1", "ok": true}]}}}

An ended request with error set failed; stopped: "input_required" means it waits on a person. See Run outcomes. Instead of polling, you can register a webhook for run.completed and run.failed.

List agents

GET /v1/agents without parameters returns every agent. For an account with many, page and filter:

bash
curl -si "https://run.camelai.com/v1/agents?limit=50&status=failed&subAgents=exclude" \
  -H "Authorization: Bearer $CAMELAI_API_KEY"
Parameter
limitA page of at most this many (1 to 200), by id. While more match, the X-Next-Cursor response header holds the next page's cursor
cursorThe previous page's X-Next-Cursor
workspaceIdOnly agents in this workspace, or unassigned for agents in none
statusrunning (loaded now, idle or not), failed (a run failed in the last 24 hours) or expiring (has an expiresAt)
subAgentsonly (agents a delegate or spawn_agent call made) or exclude
qPart of the name, key or id, ignoring case (at most 200 characters)

Each agent has id, key (null for one made without), name, type, model, configHash, connected (whether a process serving its tools is connected), running, expiresAt, parentAgentId for a sub-agent, workspaceId, lastActiveAt (when its latest run ended, ms since the epoch) and lastError: {at, class} of its latest failed run, where class says how it failed (such as spend_limit, aborted, resume_limit or model_error), never the error's text.

Endpoints

Conventions

  • Errors are {"error": "<message>", "code": "<CODE>"}. Switch on code, not the message. See Errors.
  • Every POST that changes something takes an Idempotency-Key header. A retry with the same key, path and body gets the first answer again, for 24 hours.
  • Every 429 and 503 has Retry-After.