Skip to main content
Use the Box Public API from services, CI jobs, hosted workers, and product automation code. For typed clients, start with the Box SDKs, Python SDK, or TypeScript/JavaScript SDK.
  1. Create a Box API key in the dashboard.
  2. Create a box with POST /boxes, or resume/fork an existing box when the user is continuing prior work.
  3. Poll GET /boxes/{boxId} until the box is ready or idle.
  4. Queue work with POST /boxes/{boxId}/prompt.
  5. Read GET /boxes/{boxId}/events while work is running.
  6. Use POST /boxes/{boxId}/desktop when the user or your support team needs live computer-use visibility.
  7. Stop/archive, resume, fork, or delete the box according to your retention policy.

Base URL

https://ascii.dev/api/box/v1

Authentication

Pass a Box API key as a bearer token on every request:
curl -sS "https://ascii.dev/api/box/v1/boxes" \
  -H "Authorization: Bearer $BOX_API_KEY"
Create and rotate service keys in the Box dashboard or through the v1 API key endpoints. For key lifecycle guidance, see API Keys.
Treat Box API keys and returned desktop URLs as secrets. Desktop and VNC URLs can contain access tokens and should not be logged or persisted unredacted.

Response envelope

Every v1 JSON response has an explicit success discriminator:
{
  "ok": true,
  "type": "box.list",
  "boxes": []
}
FieldDescription
oktrue for success, false for failure.
typeStable response or event discriminator, such as box.list, box.created, box.stopping, or prompt.queued.

Error model

HTTP status remains authoritative. Error bodies also use a structured JSON envelope:
{
  "ok": false,
  "type": "box.error",
  "status": 409,
  "code": "provider_not_configured",
  "message": "Prompting is locked until Codex is configured on the Agents page.",
  "error": {
    "code": "provider_not_configured",
    "message": "Prompting is locked until Codex is configured on the Agents page.",
    "status": 409,
    "details": {
      "provider": "codex",
      "setupUrl": "https://box.ascii.dev/dashboard?tab=agents"
    }
  },
  "requestId": "req_..."
}
StatusTypical codesWhat to do
400invalid_json, prompt_required, provider_required, invalid_name, no_changes, machine_not_runningFix the request body, wait for the box machine to start, or retry once the box reaches a runnable state.
401unauthorizedProvide a valid bearer token.
402billing_requiredSend the user to the returned billing URL.
404not_foundRefresh local state; the box or key no longer exists.
409account_not_ready, provider_not_configured, box_not_promptable, resume_failed, fork_failedResolve the prerequisite or resource-state conflict.
429rate_limited, daily_limit_reached, limit_reachedBack off and show the limit message.
5xxinvalid_json_response, stream_failed, http_500Retry idempotent calls with jitter and include requestId in support logs.

Box lifecycle

A Box moves through these states:
StateMeaningClient behavior
provisioning, provisioned, cloningThe sandbox is being created or prepared.Poll GET /boxes/{boxId}.
ready, idleThe box can accept prompts and interactive access.Prompt, open desktop, SSH, or inspect events.
runningThe Box is actively working.Read events; interrupt only when the caller intends to stop current work.
archivingStop/snapshot is in progress.Poll until archived or another terminal state.
archivedThe machine is stopped; a snapshot may be available.Resume or fork.
errorProvisioning or runtime failed.Show the error and let the user stop, delete, resume, or fork when allowed.

Providers, models, and reasoning

POST /boxes/{boxId}/prompt accepts the same providers Box uses in the dashboard. The API accepts codex and claude-code; claude is accepted as an alias for claude-code by the current backend, but claude-code is the canonical value to store in integrations. Model ids come from the same catalog used by the dashboard model selector. If you omit model, Box uses the user’s saved dashboard default for that provider. Prefer the listed model ids for predictable behavior.
ProviderModelsReasoning effort valuesDefault
codexgpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codexnone, low, medium, high, xhigh (gpt-5.3-codex supports low, medium, high, xhigh)gpt-5.4
claude-codeopus, sonnet, haikuopus: low, medium, high, max; sonnet: low, medium, high; haiku: no reasoning controlsonnet
Use the dashboard’s provider setup page to configure credentials before prompting. If credentials are missing, the API returns provider_not_configured with a setup URL.

Request examples

Set shared variables:
export BOX_API_BASE="https://ascii.dev/api/box/v1"
export BOX_API_KEY="box_your_secret_here"
Create a one-hour box and store its id:
BOX_ID=$(curl -sS -X POST "$BOX_API_BASE/boxes" \
  -H "Authorization: Bearer $BOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ttlSeconds":3600}' | jq -r '.box.id')
Create a box without automatic archival:
curl -sS -X POST "$BOX_API_BASE/boxes" \
  -H "Authorization: Bearer $BOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ttlSeconds":null}'
Poll readiness:
curl -sS "$BOX_API_BASE/boxes/$BOX_ID" \
  -H "Authorization: Bearer $BOX_API_KEY"
Prompt a Box to work in a repo:
curl -sS -X POST "$BOX_API_BASE/boxes/$BOX_ID/prompt" \
  -H "Authorization: Bearer $BOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "codex",
    "model": "gpt-5.4",
    "reasoningEffort": "medium",
    "prompt": "Work on the selected repo: run tests, fix failures, commit the result, and report the preview URL if you start a server."
  }'
Read Box work and lifecycle events:
curl -sS "$BOX_API_BASE/boxes/$BOX_ID/events" \
  -H "Authorization: Bearer $BOX_API_KEY"
Get a desktop streaming URL for live inspection:
curl -sS -X POST "$BOX_API_BASE/boxes/$BOX_ID/desktop?vnc=1" \
  -H "Authorization: Bearer $BOX_API_KEY"
To return a VNC URL that does not require an access token, send:
curl -sS -X POST "$BOX_API_BASE/boxes/$BOX_ID/desktop?vnc=1" \
  -H "Authorization: Bearer $BOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"publicAccess":true}'
Stop/archive a box when the workflow is complete:
curl -sS -X POST "$BOX_API_BASE/boxes/$BOX_ID/stop" \
  -H "Authorization: Bearer $BOX_API_KEY"

Endpoint reference

EndpointReference
GET /meGet current Box user
GET /limitsGet Box limits
GET /reposList GitHub repositories available to Box
POST /reposSelect repository for Boxes
GET /api-keysList API keys
POST /api-keysCreate API key
DELETE /api-keys/{apiKeyId}Revoke API key
POST /api-keys/{apiKeyId}/rotateRotate API key
GET /secretsGet Box secrets setup
POST /secretsUpdate Box secrets setup
GET /boxesList boxes
POST /boxesCreate box
GET /boxes/{boxId}Get box
PATCH /boxes/{boxId}Update box
DELETE /boxes/{boxId}Delete box
POST /boxes/{boxId}/stopStop and archive box
POST /boxes/{boxId}/resumeResume box
POST /boxes/{boxId}/forkFork box
POST /boxes/{boxId}/promptPrompt Box
GET /boxes/{boxId}/eventsList box events
POST /boxes/{boxId}/interruptInterrupt running work
POST /boxes/{boxId}/desktopGet desktop streaming URL
POST /boxes/{boxId}/sshkeyConfigure box SSH key