API reference

Run autonomous tasks on managed machines, compose them into workflows, and drop to prediction primitives only when you need direct control.

llms.txt

Introduction

Start with a task run: give Coasty a goal and a machine, then let the agent drive to completion. Use workflows when an automation needs many tasks, branches, loops, approvals, or shared outputs. Machines provide the managed computer those tasks operate.

task run

workflows

Machines

The prediction endpoints are lower-level primitives for teams that need to own the control loop themselves. Use sessions for a stateful screenshot loop, predict for a stateless step, grounding for coordinates, and parse for structured actions. Everything is normal HTTPS to https://coasty.ai/v1, so you can choose the highest-level surface that fits the job and drop down only when you need finer control.

sessions

predict

Authentication

Every API-key-authenticated request must include your secret key. The four health probes are public, and webhook ingress uses its documented Coasty-Signature HMAC credential instead. For API-key operations, the canonical form is the X-API-Key header, but Authorization: Bearer <key> works too: a blank X-API-Key falls through to the Bearer header. Pick one form and send the raw key. Do not paste the literal text Bearer  inside X-API-Key; that is the single most common first-day mistake and it returns 401 INVALID_API_KEY. Keys are created and revoked from the API keys page. Treat a key like a password: keep it server-side, store it in an environment variable, and never commit it or ship it in client-side code.

API keys

Run your first task

Your first autonomous task needs an API key and a machine. Grab a test key from the API keys page (it never bills), then use an existing machine or provision one. Set the key in your shell:

API keys

provision one

Start the task with POST /v1/runs. Replace the example machine_id, describe the outcome in task, and send an Idempotency-Key so a retried create cannot start a duplicate run. The complete example starts the run and follows it to a terminal state:

The create response begins at queued. Coasty then drives the machine, records each step, and finishes as succeeded, failed, cancelled, or timed_out. Your application can poll, subscribe to the event stream, or receive signed webhooks; it does not need to execute each prediction itself.

Task runs

Streaming events

Workflows

Prediction primitives

Task runs

A run hands the agent a task and a machine, then drives it to completion on our side. The agent loops autonomously, verifies its own work (pass or fail), can pause for a human when it hits a wall, bills $0.05 per completed step from your dollar API wallet ($0.08/step on the legacy v1 engine), and streams every event live. You start one call and watch, instead of running the predict loop yourself.

Create a run with POST /v1/runs. The two required fields are machine_id and task. The response is an agent.run object with status of queued, plus a one-time webhook_secret you store to verify webhooks. Send an Idempotency-Key header to make a retried create safe.

webhooks

Streaming events

GET /v1/runs/{id}/events returns a Server-Sent Events stream so you can follow a run as it happens, instead of polling. Each event has a type and a numeric id (the sequence number). If your connection drops, reconnect and replay everything you missed by sending the last sequence you saw as a Last-Event-ID header, or as the ?after= query parameter. The stream closes after the done event.

Human takeover

Some steps need a person: a captcha, a one-time code, a judgment call. When the agent reaches one and on_awaiting_human is pause, the run moves to awaiting_human and emits an awaiting_human event with a reason. A human completes the blocking step (in the same machine session), then you hand control back with POST /v1/runs/{id}/resume and an optional note. Resume is only valid while the status is awaiting_human.

Webhooks

Pass a webhook_url (https only) when you create a run and we POST a signed callback at each lifecycle transition. The response to your create call includes a webhook_secret exactly once: store it, because every callback is signed with it. Each request carries a Coasty-Signature header of the form t=<unix_ts>,v1=<hex>.

To verify, build the signed payload as "<t>." + raw_request_body, compute HMAC-SHA256 over it keyed by the webhook_secret, and compare against v1 with a constant-time check. Always hash the raw body bytes, before any JSON re-serialisation.

Bring your own model

By default every LLM call in the computer-use harness runs on Coasty's managed models. BYOK (bring your own key) flips that: opt in and the entire harness (the worker, grounding, the code agent, and compaction; every LLM call) runs on your own Anthropic or OpenAI account instead. Opt-in is always explicit, per request or per stored key. provider: "managed" (or omitting llm entirely) keeps the platform default, unchanged.

There are two ways to hand over a key. Store it once with PUT /v1/llm/keys/{provider} (encrypted with AES-256-GCM at rest; only a sha256-prefix fingerprint is ever echoed back), or send it per request in headers. A header key takes precedence over the stored key. Sending a key without a provider returns 422.

The headers work on POST /v1/predict, POST /v1/runs, POST /v1/workflows/{id}/runs, POST /v1/sessions, and POST /v1/schedules. Stored keys are managed through three endpoints, gated by the llm_keys scope (granted to new live keys by default). These endpoints require a live key; sandbox keys cannot read, overwrite, or delete the production credential store:

On the request body, the same endpoints accept an llm object that selects the provider and, optionally, a model per harness role. It deliberately has no api_key field (a 422 if you attempt one): keys ride headers or the encrypted store only, so they can never be echoed in run objects, webhooks, or idempotency replays.

Per-role overrides exist for tuning cost against quality: run compaction on a cheaper model while the worker stays on the default, for example. For runs, workflows, and schedules the key is snapshotted encrypted into the run, so crash-recovery on another replica keeps using your key; it is scrubbed the moment the run reaches a terminal state. GET /v1/runs/{id} echoes a non-secret llm block: {provider, model, key_fingerprint, key_source, key_scrubbed}. Schedules store only the non-secret preference; at fire time the current stored key is used. Delete the stored key and future firings fail loudly with LLM_KEY_NOT_CONFIGURED; they never silently run on platform keys.

Billing: Coasty's per-call and per-step platform charges are unchanged with BYOK. The model tokens are billed by your provider account directly.

Workflows

A workflow composes many runs into one versioned program, with branching, loops, and guards expressed as a JSON DSL. Each task step is itself an agent run, so a workflow is the way to chain tasks, gate them on conditions, and pass results between them. Workflows are versioned: re-creating the same slug bumps the version, and a PUT does too.

Create one with POST /v1/workflows. The slug must match [a-z0-9_-]. The response is a Workflow carrying an id, a version, and the current dsl_version (2026-06-01).

Workflow DSL

Workflow DSL

The DSL (dsl_version 2026-06-01) is a JSON object with a steps array and an optional output. Each step has an id and a type. A task step runs the agent and binds its result ({ status, passed, result, run_id, steps, error }) under both its save_as name and its step id, so later steps can read it.

Conditions are structured rather than expression strings, which keeps them injection-safe. Each left, right, or value is either a literal or a {{path}} reference. Paths are dotted lookups into inputs., vars., and any step id or save_as name.

A definition is validated before it is accepted. The limits below are enforced at create and ad-hoc time, so an invalid definition is rejected with 422 VALIDATION_ERROR rather than failing mid-run.

Running workflows

Start a saved workflow with POST /v1/workflows/{id}/runs, or run a definition inline (without saving) with POST /v1/workflows/runs by adding a definition (and optional inputs_schema) to the same body. Both return a workflow.run. The body accepts inputs, a default machine_id for task steps, and the budget_cents, max_iterations, and deadline_seconds guards. An Idempotency-Key header is honoured here too.

Provisioning

A machine is a Coasty-managed cloud VM that an agent can see and control. You provision one, poll until it is running, then either hand it to a task run (the agent drives it to done) or drive it yourself with the action endpoints. Machines are optional: /predict, /sessions, and /ground run against your screen. You only need a Coasty machine when you want the agent to execute on a VM Coasty hosts.

task run

action endpoints

Provision with POST /v1/machines. Only display_name is required; everything else has a sensible default. The body rejects unknown fields, so a typo returns 422 VALIDATION_ERROR rather than being silently ignored.

Lifecycle &amp; TTL

Provisioning is asynchronous. The response returns immediately with the machine in creating status and a connection object whose secrets are redacted. The VM is not drivable yet — poll GET /v1/machines/{id} until status is running before you send actions or start a run.

The machine object — returned by provision, list, and get:

List your machines with GET /v1/machines (newest first, ?limit= 1–200, default 50) — it returns { data, has_more, request_id }. Fetch one with GET /v1/machines/{id}. Both read straight from the registry, so they keep working even when provisioning is busy.

Lifecycle & TTL

A machine moves through a small set of statuses. status is the field you poll: drive the machine only while it is running. The runtime rate that applies in each status is shown below; exact per-hour USD numbers are in the Pricing section.

Pricing

Start, stop, restart are POST /v1/machines/{id}/start (and /stop, /restart). They are asynchronous: the call returns a transitional status (starting / stopping) and you poll until it settles. They are state-checked — starting a machine that is already running, or stopping one that is not running, returns 409 INVALID_STATE with current_state and allowed_from in the body, so you can react without guessing. start is allowed from stopped or error; stop only from running.

Terminate with DELETE /v1/machines/{id}. This is permanent — the VM and its disk are destroyed and a later GET returns 404 MACHINE_NOT_FOUND. Delete is idempotent: deleting an already-gone machine still succeeds, so retries are safe.

Auto-destroy (TTL). A machine left running bills until you destroy it, so set ttl_minutes as a safety net. A background sweep (every ~60s) terminates a machine once its auto_destroy_at passes. Adjust it any time with PATCH /v1/machines/{id}: ttl_minutes is measured from now (so it doubles as a lease extension), accepts 5–10080 (5 min to 7 days), and 0 clears auto-destroy entirely. Anything else is 400 INVALID_TTL. Provisioning without a TTL works but adds a Warning response header nudging you to set one.

Runtime billing. Machines bill the developer API wallet (separate from any subscription credits) by the minute, rounded down to whole credits in your favour. Running Linux is $0.05/hr, running Windows $0.09/hr, and a stopped or suspended machine the keep-alive rate of $0.01/hr; creating, error, and terminated are free. Transitional states (starting/stopping/restarting) bill at the running rate. The per-call control endpoints (actions, terminal, files, browser, screenshot, connection) are never billed — you pay for runtime only.

Connect & control

Once a machine is running you can reach it three ways: connect directly over SSH/VNC, drive it through Coasty's control endpoints, or hand it to an agent run. Normal machine responses redact secrets and only expose has_ssh_key / has_vnc_password booleans plus ports.

Connection secrets. GET /v1/machines/{id}/connection returns the full ssh_private_key_pem, vnc_password, public IP, and ports. It is gated by the opt-in connection:read scope (not granted by default — request it when you mint the key), and the response is sent Cache-Control: no-store. Treat that payload like a password: never log it. SSH usernames are ubuntu on Linux and Administrator on Windows; VNC details exist only on desktop_enabled machines.

Screenshots & snapshots. GET /v1/machines/{id}/screenshot returns the current screen of a desktop machine (a still-booting VM returns 502 SCREENSHOT_FAILED — poll for running first). POST /v1/machines/{id}/snapshot captures a restorable image (Linux), needs the snapshots:write scope, and is the one machine op with a flat fee ($0.01 per snapshot). A conclusive pre-creation failure is refunded, confirmed by X-Credits-Refunded. A timeout, an upstream 5xx, or malformed post-dispatch result may already have created the image and instead returns terminal 503 SNAPSHOT_OUTCOME_UNKNOWN without a blind refund or re-execution. Boot a future machine from a confirmed snapshot with restore_from_snapshot: true.

The control surface. Drive the VM directly with these endpoints. Each enforces a specific scope, and the high-risk ones — browser_execute (arbitrary JS) and anything under connection:read — are opt-in. /actions/batch runs up to 50 steps and stops on the first error by default (stop_on_error: false to continue); /terminal truncates output to 5000 chars.

Idempotency & safety. The machine operations in the exact reserve-and-replay set — provision, snapshot, actions, action batches, browser, terminal, and file operations — accept an Idempotency-Key (≤128 chars). Lifecycle start/stop/restart, TTL updates, and termination do not. For supported operations, a duplicate key replays the original result without re-executing; a duplicate that arrives while the first is still running waits up to ~25s, then returns 409 IDEMPOTENCY_IN_FLIGHT. One nuance worth knowing: a command that never reached the VM (a dispatch failure) is not cached, so retrying the same key runs it fresh; a command the VM actually ran (even if it errored) is cached. Every machine lookup is ownership-scoped, so a wrong or someone-else's id returns 404 — never a leak. Full code list in Errors.

Errors

Predict

POST /v1/predict is the low-level, stateless prediction primitive. Each call is independent: you provide the full context, execute the returned actions, capture the next screenshot, and decide when to call again. Use it when your application must own that loop. For an autonomous goal, start a task run. When a manually driven loop needs server-side trajectory memory, reach for sessions instead.

task run

sessions

The response is the standard prediction shape, covered in Response format.

Response format

Sessions

A session keeps the trajectory — the running history of screenshots and actions — on our side, so each step only needs the latest screenshot and instruction. This produces better multi-step behaviour on long tasks and keeps your request bodies small. Create a session once, step through the task, then delete it to release your concurrency quota.

Grounding

Grounding answers a narrower question than predict: “where is this element?” Give it a screenshot and a description and it returns the exact x, y coordinate to target. It is faster and cheaper than a full prediction ($0.03 instead of $0.05), which makes it ideal when you already know what to do and only need a pixel to click.

The response is { x, y, usage, request_id }. Coordinates are in the same pixel space as the screenshot you sent.

Parse

Parse converts a block of pyautogui code into the same structured action objects the model returns. It is deterministic, runs no model, and is free. Use it to migrate existing automation scripts onto Coasty's executor, or to normalise hand-written steps into the canonical action schema.

Action types

Every action the model can return uses an action_type from the table below, paired with a params object. Your executor switches on the type and applies the parameters. The terminal types — done and fail — set the response status and signal you to stop looping.

Response format

Predict and session-predict return the same shape. actions is the ordered list to execute; status tells you whether to keep going (continue), stop successfully (done), or stop because the task is impossible (fail). usage reports tokens and the dollar cost of the call (cost_cents).

Billed success responses also carry two headers you can read without parsing the body: X-Credits-Charged (what this call cost) and X-Credits-Remaining (your wallet balance after it). In the body, the same numbers appear as usage.credits_charged and usage.cost_cents. On an sk-coasty-test- key both are always 0. Every response (success or error) additionally carries an X-Coasty-Request-Id header that mirrors request_id; quote it when contacting support.

On a failed billed request, X-Credits-Refunded is the authoritative confirmation that credits were returned, and X-Credits-Charged is then0. If settlement cannot be confirmed, the API returns503 BILLING_UNAVAILABLE without the refund header. Follow the error'sretry_with_same_idempotency_key field rather than retrying by status alone.

[[email protected]](/cdn-cgi/l/email-protection)

[[email protected]](/cdn-cgi/l/email-protection)

Errors

Errors return a non-2xx status and a JSON envelope under an error key. The code is stable and safe to branch on; message is human-readable and may change. Every error also carries an error.request_id (mirrored in the X-Coasty-Request-Id response header), plus error.suggestion and error.docs_url for self-service. A Link: <url>; rel="help" header mirrors docs_url. Always log the request id: it is the fastest way for us to trace a failed call.

Some codes attach machine-readable context to the body. A 402 (INSUFFICIENT_CREDITS) reports required and balance; a 403 reports required_scope and current_scopes; a 422 VALIDATION_ERROR lists the offending field path under error.details; and a 409 state conflict carries current_state with allowed_from or required_state.

Troubleshooting

Five mistakes account for almost every first-week support ticket. Each maps to one status and one fix:

Pricing

Requests are billed in US dollars from your prepaid API wallet. The charge is taken before the model runs. On a conclusive server-side failure, the API submits a refund; treat it as complete only when X-Credits-Refunded is present. Ambiguous provider mutations may retain the debit until reconciliation. Internally each request unit is $0.01 (the granularity behind every price below), but everything you pay and see is dollars. Every price on this page is exact; test keys (sk-coasty-test-) always bill $0.00.

Surcharges

Four fixed surcharges can apply on top of a base price, all on the vision endpoints (predict, session steps, ground). Each is an exact USD amount:

Machines

Machines bill for runtime only, metered per minute and rounded down: $0.05/hr for a running Linux machine, $0.09/hr for a running Windows machine, and $0.01/hr while stopped or suspended. The starting, stopping, and restarting transitions bill at the running rate; the creating, error, and terminated states bill nothing, and TTL auto-destroy is free. Snapshots are a one-time $0.01 each, and every per-call operation (actions, batch, browser, terminal, files, screenshot, connection) is free. Provisioning requires a $0.20 wallet minimum, which is a gate, not a charge. If the wallet empties mid-flight the machine is automatically stopped, never destroyed, and resumes after you top up. The live rate card is always at GET /v1/machines/pricing.

Schedules

Schedules have no per-fire fee: webhook fires are free (limited to 60/min), and create, run-now, and webhook fires only require the same $0.20 wallet minimum as a gate. The execution itself is billed differently from everything else on this page: scheduled agent runtime is charged to your subscription credit balance at 10 credits per minute ($0.10 of subscription value per minute, at 1 credit = $0.01), not to this USD API wallet. Keep both balances funded if you rely on schedules.

Create an API key

View your usage

Cookbook

Curated open-source repositories for building on the Coasty API. Clone a repo, mint a key, and ship.

coasty-ai/computer-use-cookbookComputer Use CookbookRunnable, copy-paste examples for every part of the Coasty API: predict, sessions, task runs, workflows, and driving machines. Start here.ExamplesPythonNodecURLView on GitHub

Computer Use Cookbook

Runnable, copy-paste examples for every part of the Coasty API: predict, sessions, task runs, workflows, and driving machines. Start here.

coasty-ai/open-coworkOpen CoworkThe open-source Coasty project for computer-use agents that work alongside you. Build on it, fork it, or contribute.Open sourceAgentsReference appView on GitHub

Open Cowork

The open-source Coasty project for computer-use agents that work alongside you. Build on it, fork it, or contribute.