Skip to content

Trigger an automation through the API

On this page

An API automation lets a script or another service start an agent task by sending an HTTP request. For example, a monitoring service could ask an agent to investigate a failed check in your project.

Create and call the trigger

  1. In your project's Automations section in the desktop app, choose New automation, then choose the API trigger.
  2. Enter a name and prompt, review the agent and model settings, and choose Create. The automation will start paused.
  3. In API setup, review Request mode. Keep Configurable to let callers change the task for each run, or choose Fixed defaults to accept only the saved task.
  4. Choose Generate secret. Copy the secret and the Run endpoint into the calling service's secure configuration, and keep both private: anyone with the endpoint and secret can start work using the automation's project access and usage allowance.
  5. Choose Activate to allow API requests.
  6. Send a POST request to the run endpoint with a JSON body and an Authorization: Bearer <secret> header.

For an initial test, set AUTOMATION_RUN_URL to the automation's Run endpoint and AUTOMATION_SECRET to the secret you generated, storing both securely on the calling system, then run:

curl --request POST "$AUTOMATION_RUN_URL" \
  --header "Authorization: Bearer $AUTOMATION_SECRET" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: test-run-001' \
  --data '{}'

The empty JSON object will use the saved prompt and agent settings in either request mode. You can also copy an example from Request examples in the automation's API setup section.

The optional Idempotency-Key header prevents retries from starting duplicate runs. Choose a new key for each intended run. If you don't know whether a request succeeded, retry with the same key and input to receive the original run. Reusing a key with different input will return a conflict.

Choose fixed or configurable input

Under Request mode, choose Fixed defaults when every call should use the saved task; this mode accepts only {}. Choose Configurable when the calling service needs to change the task or agent settings for each run. Configurable requests accept these optional fields:

FieldMeaning
promptReplaces the saved prompt for this run; it is not appended.
threadTitleNames the new thread without renaming the automation.
executionReplaces the agent, model, reasoning, and speed settings.
targetStarts the new thread on an existing devbox created by this automation. Omit it to create a new devbox.

For example, send this body to change only the task and thread title:

{
  "prompt": "Investigate the failing billing tests and report what changed.",
  "threadTitle": "Billing test investigation"
}

Omitted top-level fields will keep their saved defaults. If you supply execution, include a complete selection with backend, model, and reasoningEffort; individual execution fields are not merged with the defaults. Use codex or claude for backend, and a model and reasoning combination offered in the product. For Claude models without a reasoning control, use null for reasoningEffort. To copy a complete, valid execution example with current model options, use Request examples in API setup.

Codex also accepts serviceTier: standard or fast. Omitting it will select standard. Claude does not accept serviceTier. Unsupported combinations, unknown fields, incomplete selections, and raw agent CLI arguments will be rejected before a run is created.

Your Request mode choice is saved as soon as you select it. Switching from Fixed defaults to Configurable will rotate the secret, because the change widens what a caller can do: with the new secret, callers can give the agent arbitrary instructions and use anything the agent can access on the devbox. Copy the replacement secret into the calling service.

Start workflows on the same devbox

For one devbox per issue, start the first run without target. Wait for its status to reach thread_ready, then save the returned devboxId with the issue. Send later workflows to the same run endpoint with a new idempotency key and, for example, this body:

{
  "prompt": "Implement the plan saved in issue-plan.md.",
  "threadTitle": "Build the feature",
  "target": { "kind": "existing_devbox", "devboxId": "<saved devboxId>" }
}

Each request creates a separate run and conversation on the same filesystem. The new thread does not inherit another thread's conversation; save plans and handoffs in files or include them in the prompt. Threads can run concurrently, so coordinate workflows that edit the same files or change branches.

Only devboxes created by this automation can be targeted. A missing, still starting, archived, destroying, or inaccessible target returns 409 devbox_unavailable; the request will not create a replacement devbox. If the target becomes unavailable after acceptance, the run can fail during startup. Check its status URL for details.

A sleeping target will wake if capacity is available. Reusing an awake devbox does not need another awake slot. The option to sleep an idle devbox applies to new-devbox requests; a blocked wake will instead appear as a failed run with startup_active_fork_limit_reached.

Choose Never under Devbox cleanup to retain an issue's devbox between workflows. Cleanup follows the first run's setting, and automatic cleanup keeps a devbox once another thread has started on it. Runs sharing a devbox appear in one sidebar group; each run remains available in run history.

Follow the accepted run

An accepted request returns HTTP 202 with JSON describing the launch. These are the main fields:

FieldMeaning
runPublicIdThe ID of the run that was created.
statusUrlThe URL to check the run's launch status.
statusstarting, thread_ready, failed, or skipped.
effectiveThe threadTitle, backend, model, reasoningEffort, serviceTier, and promptSource selected for this run.
clientThreadIdThe created thread's ID, or null before the thread exists.
devboxIdThe devbox ID once assigned, otherwise null. Wait for thread_ready before using it as a target.
statusReasonCode, statusReasonMessageDetail about the status when available, otherwise null.
idempotentReplaytrue when the response returns the original run for a retried idempotency key.
requestIdAn identifier for this request.

The status endpoint reports launch progress. It does not return the prompt, agent completion status, or final answer. Open the run's thread from the automation in boxes.dev to read the agent's work.

To check launch progress, set AUTOMATION_STATUS_URL to the response's statusUrl value, then send a GET request with the same secret:

curl "$AUTOMATION_STATUS_URL" \
  --header "Authorization: Bearer $AUTOMATION_SECRET"

The thread_ready status means the run's thread exists and can be opened; the agent may still be working on its first response. Independent requests can start runs in parallel, subject to your awake devbox limit; an idempotency key only groups retries of the same request.

If a request is rejected, check that the automation is active and has no reported error, then check your awake devbox capacity. Draft and paused automations do not accept API runs. For the option to sleep an idle devbox to make room, see capacity behavior.

Rotate access and test changes

If the secret is exposed, choose Rotate secret in API setup and update the calling service with the replacement. Keep secrets out of documents, tickets, repositories, agent prompts, and public URLs.

After changing the saved prompt, agent settings, or capacity options, choose Save changes. Then send a representative request with a new idempotency key, check the settings returned in the response, and inspect the resulting thread.