Runs
Start work and follow it to the end. Statuses, step telemetry, and bindings are explained on Runs and steps.
POST /v1/runs
Start a run. Returns 201 immediately with status pending; the work happens asynchronously.
curl -X POST https://api.esy.com/v1/runs \
-H "Authorization: Bearer $ESY_API_KEY" \
-H "content-type: application/json" \
-d '{
"templateId": "generate-illustration",
"workspaceId": "9a1b6d4c-…",
"intake": {
"prompt": "a lighthouse at dusk, storm rolling in",
"style": "flat",
"aspectRatio": "4:3",
"categories": "landscapes"
},
"providers": { "imageGenerator": "openai/gpt-image-2-2026-04-21" }
}'Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | string | required | The workflow id, e.g. generate-illustration. Find one in the catalog. |
intake | object | required | Must satisfy the workflow’s intakeSchema, or you get a 422 naming each bad field. |
workspaceId | uuid | optional | Where the run and its costs land. Defaults to your default workspace. |
projectId | uuid | optional | Optional project inside that workspace. |
providers | object | optional | Role → model-registry id, for this run only. Validated against GET /v1/models. |
templateId and providers. Unknown keys are ignored, so a body using workflowId fails with 422 templateId required, and one using providerOverrides silently runs with the default models.Errors
404 unknown workflow · 400 deprecated workflow or bad provider override · 403 workspace out of reach · 422 invalid intake · 402 a budget refused it. Bodies for each are on Errors.
GET /v1/runs
List runs, newest first.
curl -s "https://api.esy.com/v1/runs?workspaceId=$WS&status=failed&limit=20" \
-H "Authorization: Bearer $ESY_API_KEY"| Field | Type | Required | Description |
|---|---|---|---|
workspaceId / projectId | uuid | optional | Scope the list. |
status | string | optional | One of the nine run statuses. |
parentOrderId | string | optional | The children of one order. |
workerId | string | optional | Runs a worker started. |
includeArchived | boolean | optional | Archived runs are hidden by default. |
offset / limit | integer | optional | Pagination. limit is capped at 100. |
GET /v1/runs/{run_id}
Read a run: status, intake, pinned version, step telemetry, and costs.
The full shape, with real values, is on Runs and steps. Poll this until the status is terminal, or stream run events instead.
POST /v1/runs/{run_id}/cancel
Cancel a run at its next step boundary.
Stops future spend. Provider calls already made stay billed. The run ends as cancelled.
POST /v1/runs/{run_id}/archive
Hide a terminal run from lists.
Archive, never delete: the run keeps its steps, costs, and artifact, and reappears with includeArchived=true. Only terminal runs can be archived.
PATCH /v1/runs/{run_id}/project
Move a run to a different project in the same workspace.
curl -X PATCH https://api.esy.com/v1/runs/run-fb0677b2/project \
-H "Authorization: Bearer $ESY_API_KEY" \
-H "content-type: application/json" \
-d '{ "projectId": "b1126320-…" }'projectId must be present; send null to move the run to the workspace level. Costs follow the run.
POST /v1/runs/{run_id}/finalize
Recover a run whose steps all completed but whose finalization never ran.
A rare recovery tool. If the process running a run dies between the last step and the bookkeeping, the work is done and paid for but the run never reaches a terminal status. This writes the artifact and the terminal status from what was already recorded — no step is re-run.