Run an agent loop
One call that drives this computer until the task is done: the loop screenshots, asks a model what to do, performs it, and repeats. Answered by the control plane rather than forwarded to a hypervisor, and it can run for minutes.
The computer must already be RUNNING. This endpoint will not start one for you: starting is billable, and it is not a decision to make on somebody’s behalf because they sent a prompt. A stopped or suspended computer is refused with status 409, and so is one another agent run is already driving — that one with reason: "contention", because it ends when the other run does, as does one whose disk is still being made.
WITH STREAMING, THE DEFAULT, THOSE REFUSALS ARRIVE ON A 200. Every refusal found after the request is accepted — an unknown computer (404), one not running or already driven (409), a credential refused part way through, the model API’s own errors, and on an OpenAI run a batch, bash command or screenshot that failed — arrives on the stream as event: error with {request_id, error, status, reason?, cost_usd?, top_up_url?, usage, steps}, where status is the status it would have had and steps is the LIST of AgentSteps taken before it failed — the list stream: false calls steps_taken, not the count AgentResult.steps carries on done (an unexpected failure of the stream itself sends {request_id, error, status: 500} alone). Only stream: false answers them as HTTP statuses. What is checked before the request is accepted — the key, the role, the rate budget, the body, X-Model-Key — is an HTTP status either way.
Send X-Model-Key to use your own Anthropic or OpenAI key. The key is never stored; the provider bills you directly and no Mandala AI credits are spent. Select OpenAI with a gpt-*, o-series or computer-use-preview model, or provider: openai. A key whose prefix belongs to the other provider — an sk-ant- key for OpenAI, or any other sk- key for Anthropic — is a 400. OpenAI uses the Responses API with native computer batches and a bash function on this desktop. It sends prompts, screenshots and command output to OpenAI, using stored responses to continue the run. Each OpenAI batch is admitted in full against max_steps and the rate budget before any action runs; a batch that exceeds the remaining allowance is not partially executed. A batch, bash command or screenshot that fails ends an OpenAI run as a failure rather than with a stop: it carries the status, message and any reason the platform answered that call with, and the steps already taken — for a batch, the actions the desktop acknowledged, and the failed one with its error when the desktop said which it was. Nothing is replayed, so inspect the desktop before continuing. A command that runs and exits non-zero is not a failure; its output goes back to the model. OpenAI requires your own key. Funded runs are metered by Mandala. Without that header, eligible accounts can use funded AI credits when enabled. Funded runs require a plan, a supported Stripe billing country, and at least $0.25 available for the first model call; otherwise they are refused before streaming (402 with top_up_url for insufficient credits; 400, 403 or 503 otherwise, as each of those statuses says). Funded runs use the platform system prompt and tools, default to claude-sonnet-5-5, and also allow claude-opus-5-5. Custom system prompts and other initially selected models require your own key. Anthropic default fallback routing is enabled and can serve a broader model; each billed attempt uses that model’s rate. Each model call reserves $0.25, then settles actual usage at 1.3× list price (deployment configurable). A completed call can overrun its reserve or max_cost_usd; its full cost is charged before another call is admitted. Usage beyond remaining credits creates debt that survives credit expiry; future grants and top-ups settle it first. If credits become unavailable mid-run it ends with credits_exhausted; the cost cap ends with max_cost. Solo/Studio/Swarm monthly grants are $5/$10/$50 and expire at billing-period end. $10/$25/$50 top-ups expire 12 months from purchase. Without a plan, existing credits freeze while their original expiry continues; a purchase paid after plan removal is retained for issuance on resubscription if unexpired. Funded prompts, screenshots and tool results are sent to Anthropic under Mandala’s account. See pricing, terms and subprocessors.
The response STREAMS as text/event-stream by default, because a run can go a long time between anything worth saying and a buffered answer would be a minute of silence followed by everything at once. Send stream: false for a single JSON body at the end instead. On the hosted API a request that is not streaming is cut off at the edge after about 120 seconds (a 524 with no body), and the run’s result — its usage and the steps it took — is lost with it. The run is stopped where it was once the dropped connection reaches the platform, so do not assume it finished. Keep streaming, the default, for anything that may take longer.
A RUN IS KEPT IN A THREAD. Unless you send store: false, a run that acted on the desktop, or finished with an answer, is kept as one exchange — the prompt, and the run’s closing text and how it ended (aborted for one stopped part way, which may have done more than it reported) — in a thread on this computer, and its thread_id comes back on done (or the stream: false body) and on a failure’s error. Send that thread_id with the next prompt to continue the conversation: the model is given the earlier turns (the newest 64,000 characters of them, with a note when some are left out) and told they are done, and acts only on the new prompt. A run refused before it acted keeps nothing and starts no new thread; a continuation still names the thread you sent, while it exists. An account keeps 1000 threads: a new one takes the place of the least recently used that this key could delete, and when there is none (a workspace key whose workspace holds none, say) the run is not kept and has no thread_id — delete threads you no longer need. Threads are listed and read under /agent/threads, and are deleted with their computer.
A CLAUDE RUN CAN ZOOM. Except on claude-opus-4-5 to 4-7 and claude-sonnet-4-6, which use the older computer tool, the loop serves the computer toolset’s zoom: a close-up cut from a fresh capture of the screen, of the rectangle the model names in the last full screenshot’s coordinates, so it shows the screen as it is now, which can have changed since that screenshot. A zoom is a step (action: "zoom") and counts toward max_steps. One that is refused — no full screenshot shown yet, a rectangle outside it, or a capture replaced before it could be cropped — is a step with error, and the loop continues. OpenAI runs have no zoom.
EVERY ACTION THE LOOP TAKES SPENDS YOUR RATE BUDGET, the same budget your own calls draw on. An Anthropic step costs what the calls it makes would cost you: an input and the screenshot that shows it, one call for bash, a cursor read or a bare screenshot, and two screenshots for a zoom. A key action with repeat: n is one input per press and then the screenshot, n + 1 calls, so a single step can cost up to 101 (repeat is at most 100). OpenAI reserves, before each batch runs, the price of one input call for every action in it plus one screenshot for the screenshot after it; its initial screenshot and each bash call cost one call each. A run that exhausts it stops where it is and ends with stop: "rate_limited" rather than failing: the steps already taken are reported, and the work already done to the desktop stands. Treat it the way you treat max_steps — as a run that did not finish — and wait rather than raising anything.
A RUN CAN BE REFUSED PART WAY THROUGH. The API key it is running on is re-checked before every model call and before every action or OpenAI batch, so a key deleted — or a membership removed — mid-run stops the run where it is. That arrives as an error event on the stream (or the single JSON body when stream is false) carrying reason: "revoked" beside error, plus the usage and the steps already taken, which are real and are billed. Most of what this endpoint refuses carries NO word: the model API’s own failures and a stopped or suspended computer arrive without one. A computer another run is already driving, like one whose disk is still being made, carries reason: "contention". The run’s opening computer lookup, and an OpenAI run’s batch, bash command or screenshot, forward whatever the platform classified its own refusal as, so any of the words above can reach you through this frame. Read it the way you read reason anywhere else here, and treat an absent word as no classification.
Requires the member role or higher.
Request
- Base URL: https://app.mandala.computer/api/v1
- URL: https://app.mandala.computer/api/v1/computers/{id}/agent
- Auth: HTTP bearer
Path parameters
The computer id.
Headers
Your own key for the selected Anthropic or OpenAI provider. Omit for eligible Anthropic-funded runs. A blank header is refused, and so is a key whose prefix belongs to the other provider (sk-ant- for OpenAI, any other sk- key for Anthropic).
Request body
Response
An SSE event log of what the loop did, or one JSON body when stream is false.
The stream’s events are step (an AgentStep, one per action), text ({text}, what the model said), done (the fields below without steps_taken: the run finished or stopped) and error (see above: the run failed; its steps is an AgentStep list, not a count). With stream: false the answer is the fields below, steps_taken included, and a run that fails answers its status with an AgentFailure body — {error, reason?, cost_usd?, top_up_url?, usage, steps_taken}.
The stream opens at once with a : run starting comment line, before the first model call, and sends : keepalive comment lines while the run goes quiet. Lines beginning : carry nothing and can be ignored.
Changes
No recorded changes to this operation across all 1 revision of this API.