Coasty/

Developer API

Reference

Error envelope and HTTP status codes

Errors

Errors, at a glance

Error envelope and HTTP status codes

error.code + retryable + request_id
Error envelopes tell clients whether a request is retryable, whether the same idempotency key is required, and how to reconcile state.

Errors produced by the Coasty application 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 canonical error also carries error.request_id, error.suggestion, and error.docs_url for self-service. The X-Request-Id header identifies the current attempt. X-Coasty-Request-Id can preserve the original operation id on an exact replay, as can the replayed body. A CDN or network intermediary can fail before this envelope exists and return HTML/non-JSON instead. A Link: <url>; rel="help" header mirrors docs_url. Always log the available request ids: they are 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.

JSON
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Your API wallet does not have enough funds to complete this request.",
    "type": "billing_error",
    "suggestion": "Add funds in the dashboard, or use an sk-coasty-test- key while building (test keys never bill).",
    "docs_url": "https://coasty.ai/docs#errors",
    "required": 5,
    "balance": 2,
    "request_id": "req_8f2c1e9a",
    "retryable": false,
    "retry_with_same_idempotency_key": false
  }
}
StatusCodeCause and fix
401INVALID_API_KEYKey missing, malformed, or revoked (or "Bearer " was wrongly pasted into X-API-Key). 401s carry a WWW-Authenticate header.
403INSUFFICIENT_SCOPEThe key is valid but lacks the scope this endpoint needs. The body lists required_scope and current_scopes; re-mint a key with the scope.
402INSUFFICIENT_CREDITSYour USD wallet can't cover the request. The body reports required and balance. Add funds, or use a test key while building.
402WALLET_EXHAUSTEDThe wallet emptied mid-run. Steps that already completed were billed; top up to continue.
422VALIDATION_ERRORThe body failed schema validation. error.details lists the offending field path and the expected type.
422ACTION_POLICY_VIOLATIONA server-enforced action policy rejected the complete action batch before dispatch. Direct machine actions and Parse return this error envelope; Predict and Sessions return status=fail with a fail action carrying the same code.
422INVALID_SCREENSHOTThe screenshot is not a static PNG/JPEG encoded as raw base64 or an exact image/png or image/jpeg data URI, or it contains whitespace.
413PAYLOAD_TOO_LARGEAn individual screenshot exceeds its 10,485,760-character base64 limit, or the complete JSON request exceeds 15 MiB. Downscale/JPEG-compress frames or use a stateful session.
400INVALID_LIMITA ?limit= query parameter fell outside the allowed range of 1 to 200. The body echoes actual, min, and max.
400INVALID_EVENT_CURSORA cursor query parameter is negative. GET /v1/runs/{id}/log requires after_step to be a non-negative integer.
400INVALID_STATUS_FILTERA ?status= query parameter is not one of the real statuses for that resource.
404NOT_FOUNDThe resource id is unknown or expired. Ids are mode-isolated, so a test key can't see live resources.
404SESSION_NOT_FOUNDThe session id is unknown or its 2-hour (7200-second) idle window expired.
404RUN_NOT_FOUNDThe run id is unknown, expired, or belongs to the other key mode.
404WORKFLOW_NOT_FOUNDThe workflow id (or workflow-run id) is unknown or was archived.
409NOT_AWAITING_HUMANYou resumed a run that is not in awaiting_human. The body reports current_state and required_state.
409RESUME_CONFLICTA resume or cancel race was lost (the run already moved on). Re-read the run and retry against its new state.
422IDEMPOTENCY_KEY_REUSEDThe same Idempotency-Key was sent with a different operation, canonical body, or effective BYOK provider/model/key identity. Use a fresh key, or replay every original bound input.
409IDEMPOTENCY_IN_FLIGHTThe original keyed request is still running. Honor Retry-After and retry the identical body with the same key.
409IDEMPOTENCY_ALREADY_REFUNDEDThis key's stable wallet debit was already refunded and cannot fund new work. Use a new Idempotency-Key for a new execution.
400FEATURE_NOT_AVAILABLEA requested option is not shipped on this API surface or is unavailable on your tier. Remove the option, use a supported surface, or upgrade when the feature is tier-gated.
500INTERNAL_ERRORAn unexpected server error. Retry, and quote request_id when contacting support.
500PREDICTION_FAILEDThe prediction model run failed. X-Credits-Refunded confirms that its wallet debit was returned.
500GROUNDING_FAILEDThe grounding model run failed. X-Credits-Refunded confirms that its wallet debit was returned.
503BILLING_UNAVAILABLEThe wallet charge or refund could not be confirmed. Follow retry_with_same_idempotency_key exactly; do not infer settlement from the status alone.
503SETTLEMENT_INCOMPLETEA provider/session result crossed an irreversible boundary but final persistence is incomplete. With an Idempotency-Key, retry the identical body using that same key: a durable completion replays without provider work and a started-only outcome is never re-inferred. Without a key, another request is a new operation that may call and bill the provider again; do not auto-retry.
503UPSTREAM_UNAVAILABLEA transient upstream outage. Retry with backoff. Reuse an Idempotency-Key only when the original operation is marked reserve-and-replay and the response explicitly permits same-key retry.
504UPSTREAM_TIMEOUTAn upstream call timed out. Check the original operation's idempotency policy before retrying; unsupported mutations have no duplicate-suppression guarantee.
404MACHINE_NOT_FOUNDThe machine id is unknown, was terminated, or belongs to the other key mode. Machine ids are mode-isolated, so a test key can't see a live VM. Returned (not 403) even for someone else's id, so ids can't be enumerated.
400INVALID_MACHINE_IDThe path id is not a UUID (live) or an mch_test_<hex> id (test). Use the id returned by POST /v1/machines verbatim.
409INVALID_STATEA lifecycle action conflicts with the machine's status (e.g. start while running). The body carries current_state and allowed_from. Re-read the machine and act on its real state.
400INVALID_TTLttl_minutes must be 0 (clear auto-destroy) or 5–10080 (5 min to 7 days). A value of 1–4 or above 10080 is rejected.
409TEST_MACHINE_LIMITA test key may hold at most 5 mock machines at once. Delete one, or move to a live key for real VMs.
400UNKNOWN_BROWSER_OPThe /browser/{op} path segment is not a known browser operation. See the action surface table for valid ops.
400UNKNOWN_FILE_OPThe /files/{op} path segment is not a known file operation. See the action surface table for valid ops.
502SCREENSHOT_FAILEDThe VM could not produce a screenshot (still booting, or the desktop service is not ready). Poll until status is running, then retry.
502UPSTREAM_AUTH_FAILEDThe provisioning service rejected our internal call (a Coasty-side configuration issue, never your key). Transient from your side; honor Retry-After and retry, and quote request_id if it persists.
401INVALID_DEVICE_TOKENThe external-machine token is missing, malformed, revoked, or belongs to another machine. Re-enroll or use that machine's one-time device token; never substitute the owner API key.
401DEVICE_REVOKEDThe external machine was revoked by its owner. Stop the driver permanently; an old token cannot revive the machine.
409STALE_FENCING_TOKENThe driver is using an older lease generation. Stop executing commands and re-authenticate; a stale driver must never write observations or results.
409FRAME_SEQUENCE_CONFLICTAn observation sequence was reused with different screenshot bytes. Resume after the last accepted monotonic sequence instead of overwriting it.
409FRAME_PRECONDITION_REQUIREDA mutating external-machine action omitted the latest observed frame_id. Capture, plan one action, then submit it as precondition_frame_id.
409FRAME_PRECONDITION_MISMATCHThe supplied frame is stale, or the terminal device result did not exactly echo its envelope's precondition_frame_id (including null). Capture again and re-plan; never re-execute the input blindly.
409COMMAND_RESULT_CONFLICTA completed command id received a different terminal result. Identical replay is safe; conflicting replay is rejected.
409COMMAND_EXPIREDThe command deadline passed before its result arrived. Do not execute or acknowledge the expired action.
409COMMAND_CANCELLEDThe run or owner cancelled the command before completion. Stop local execution and do not replay it.
409MACHINE_BUSYThe external machine already has one queued or delivered command. Wait for that stable command id to finish; do not dispatch concurrently to the same physical display.
409PROTOCOL_VERSION_MISMATCHThe heartbeat protocol_version differs from the enrolled driver's protocol. Upgrade or re-enroll instead of guessing at wire compatibility.
503DB_UNAVAILABLEA backing store was briefly unreachable: the machine registry, the run event log behind GET /v1/runs/{id}/log, the schedule store behind the schedule reads, the Coasty API key store behind GET/DELETE /v1/keys, or the BYOK stored-key service behind GET/DELETE /v1/llm/keys and stored-key resolution. Transient; honour Retry-After and retry with backoff. Your stored data is unchanged, so never rotate a credential in response to this.
503SNAPSHOT_OUTCOME_UNKNOWNSnapshot dispatch may have created the machine image, but completion could not be confirmed. The keyed result is terminal and the debit is retained for reconciliation; do not retry blindly.
422LLM_KEY_NOT_CONFIGUREDYou asked for BYOK (llm.provider is anthropic or openai) but no usable key was supplied. Live auth can use the encrypted store or X-LLM-Api-Key. Test auth never reads stored live keys and returns: Stored provider keys are unavailable for test API keys. Send X-LLM-Api-Key explicitly for direct BYOK.
422LLM_KEY_INVALIDThe supplied LLM key is unusable: empty, malformed, the wrong provider's format, or a stored key that could not be decrypted. Check the key matches the provider (sk-ant-... for anthropic) and re-store it.
422LLM_MODEL_INVALIDA BYOK or legacy top-level Run model id is empty, longer than 256 characters, uses unsupported characters, or looks like a credential (sk-*, bearer/authorization, API-key, or secret form). Rejection never reflects the supplied value. Put credentials only in X-LLM-Api-Key.
404LLM_KEY_NOT_FOUNDDELETE /v1/llm/keys/{provider} found no stored key for that provider. List what you have with GET /v1/llm/keys.
422LLM_PROVIDER_UNSUPPORTEDThe provider/header combination is unsupported, or test-auth async work carried BYOK intent. Synthetic test Runs, Workflows, and Schedules return: BYOK is unavailable for synthetic test runs, workflows, and schedules. Use managed mode or a live Coasty API key.
401LLM_PROVIDER_AUTH_FAILEDYour Anthropic/OpenAI account rejected the key (their 401/403). Rotate the key in your provider console and update it with PUT /v1/llm/keys/{provider}. Never retried on platform keys.
429LLM_PROVIDER_RATE_LIMITEDYour own provider account is rate-limiting (their 429). Retryable: honor Retry-After, raise your provider tier, or reduce volume.
402LLM_PROVIDER_QUOTA_EXCEEDEDYour provider account is out of credits or quota. Top up your Anthropic/OpenAI billing; this is your provider's balance, not your Coasty wallet.
502LLM_PROVIDER_ERRORYour LLM provider returned a server error (their 5xx). Retryable with backoff; if it persists, check the provider's status page.
Branch on error.retryable, not the HTTP status alone. Some503 outcomes are deliberately terminal, includingSNAPSHOT_OUTCOME_UNKNOWN. A 500 model failure is refunded only when X-Credits-Refunded is present; after a confirmed refund, a deliberate new execution uses a new idempotency key.

Official 503/504 retry policy

For a canonical JSON error, first read retryable,retry_with_same_idempotency_key, retry_after, and code. Parse Retry-After as either delta seconds or an IMF-fixdate HTTP-date. Wait at least the largest valid server delay. If no delay is present, use full jitter: a random delay from zero tomin(30s, 1s × 2^retryIndex).

The recommended automatic client budget is four total attempts (the initial send plus three retries) and a two-minute elapsed budget after the first failure, whichever ends first. This is a client safety default, not a server guarantee. Never violate a largerRetry-After; if it does not fit the foreground budget, stop and requeue the operation for later.

Original operationAfter retryable 503/504 or transport loss
GET / HEADHonor Retry-After when present; otherwise use bounded full jitter, always within the attempt and elapsed budgets.
Mutation with retry_with_same_idempotency_key: trueUse the same Idempotency-Key with the identical method, path, body, and effective BYOK provider/model/key identity.
Mutation with same-key permission false or absentDo not automatically resend. Check execution state before retrying, then follow the code and suggestion.
IDEMPOTENCY_IN_FLIGHTStop resubmitting the mutation. Poll GET /v1/idempotency/{key} at the delay advertised by the original IDEMPOTENCY_IN_FLIGHT response. A processing lookup does not currently add its own Retry-After, so continue with bounded backoff; cap ordinary foreground reconciliation at ten minutes, then surface pending state.
Non-JSON / HTML edge responseA CDN such as Cloudflare may fail before Coasty can build an envelope. Retry reads. For a mutation, exact-replay only if it was originally sent to a documented replay-capable endpoint with a valid key; otherwise reconcile state first.

For state reconciliation, use GET /v1/runs/{id},GET /v1/workflows/runs/{id},GET /v1/machines/{id}, orGET /v1/sessions/{id}. For a generic keyed operation whose response was lost, GET /v1/idempotency/{key} can return the stored result or report that it is still processing. A missing record does not prove that an unkeyed or unsupported mutation never ran. Lifecycle actions such as run resume/cancel, workflow update/delete/cancel/resume, machine start/stop/restart/update/delete, and session reset/delete require a resource-state check before any resend.

request_id and Idempotency-Key are different. The client chooses and reuses the idempotency key for one operation; each HTTP attempt gets a current X-Request-Id. Log it, plus any distinct X-Coasty-Request-Id header or body request_id retained from the original operation by an exact replay. If an edge response has none, log UTC time, method, path, andCF-Ray when present. Never copy a request id into the Idempotency-Key header.

Troubleshooting

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

SymptomLikely causeFix
401Wrong header. The key is missing, or Bearer  was pasted into X-API-Key.Send the raw key in X-API-Key, or use Authorization: Bearer <key>. Never both prefixes.
402No credits. Your live wallet can't cover the call (INSUFFICIENT_CREDITS).Add funds, or build against an sk-coasty-test- key (test keys never bill).
403Missing scope. The key lacks required_scope for this endpoint.Re-mint a key with the needed scope (for example runs:write or workflows:write).
422Bad screenshot or missing field. Undecodable base64, an unsupported data: prefix, embedded whitespace, or an absent required field.Send raw base64 or an exact PNG/JPEG data URI with no whitespace; read error.details for the exact field path.
API reference — Coasty Computer Use API | Coasty - AI Computer-Use Agent