Orders
One workflow, fanned into many runs, under one budget. Concepts are on Generation Orders.
Lifecycle
| Status | Meaning |
|---|---|
| planned | Created and estimated. Children exist as planned runs. Nothing spent. |
| running | Started. Children are executing. |
| attention | Settled short but still fulfillable — retry, or accept the gap. |
| completed | Every child settled successfully, or the gap was accepted. |
| failed | Could not complete. |
| cancelled | You stopped it. |
POST /v1/orders
Plan an order. Returns in the planned state with an estimate; nothing executes.
curl -X POST https://api.esy.com/v1/orders \
-H "Authorization: Bearer $ESY_API_KEY" \
-H "content-type: application/json" \
-d '{
"workflowId": "generate-clip-art-asset-v2",
"workspaceId": "9a1b6d4c-…",
"intakeBase": { "style": "clay", "aspectRatio": "1:1", "categories": "woodland" },
"variationSpec": {
"resolver": "list",
"params": { "items": [ { "prompt": "a fox" }, { "prompt": "a badger" } ] }
},
"budgetLimitUsd": 2.0,
"budgetEnforcementMode": "hard_stop"
}'{
"id": "order-1f2e3d4c",
"workflowId": "generate-clip-art-asset-v2",
"workflowVersion": "2026.09.10",
"status": "planned",
"executionMode": "standard",
"estimatedCostUsd": 0.09,
"counts": { "planned": 2, "running": 0, "succeeded": 0, "failed": 0, "skipped": 0 },
"currency": "USD"
}workflowId, while runs take templateId. Same value, two field names — an inconsistency in the API, not in these docs.Body
| Field | Type | Required | Description |
|---|---|---|---|
workflowId | string | required | The workflow every child runs. |
variationSpec | object | required | How children differ. resolver is list, matrix, or csv; params supplies the values. |
intakeBase | object | optional | Intake shared by every child; variations are merged over it. |
workflowVersion | string | optional | Pin a version. Defaults to the live one. |
workspaceId / projectId | uuid | optional | Where the runs and costs land. |
targetCount | integer | optional | How many successful children you need. |
executionMode | enum | optional | standard (default) or batch — provider batch APIs, slower and cheaper. |
budgetLimitUsd | number | optional | A cap for this order alone. |
budgetEnforcementMode | enum | optional | Same modes as budgets. |
providerOverrides | object | optional | Role → model id, applied to every child. |
planArtifactId | string | optional | Links children into a pack family. |
POST /v1/orders/{order_id}/start
Start executing a planned order.
The budget is checked again here, against current spend — an order planned yesterday can be refused today with a 402.
GET /v1/orders/{order_id}
Read an order and its rollup.
counts gives planned, running, succeeded, failed, and skipped; actualCostUsd rolls up every child. To see the children themselves, list runs with GET /v1/runs?parentOrderId=….
POST /v1/orders/{order_id}/retry-failed
Re-run failed children.
curl -X POST https://api.esy.com/v1/orders/order-1f2e3d4c/retry-failed \
-H "Authorization: Bearer $ESY_API_KEY" \
-H "content-type: application/json" \
-d '{ "all": true }'Pass all: true, or name specific children. Failures classed as deterministic — the same input would fail the same way — are skipped unless you set includeDeterministic: true, because retrying them only buys a second identical failure.
POST /v1/orders/{order_id}/accept-gap
Settle an order short, deliberately, with a recorded reason.
curl -X POST https://api.esy.com/v1/orders/order-1f2e3d4c/accept-gap \
-H "Authorization: Bearer $ESY_API_KEY" \
-H "content-type: application/json" \
-d '{ "reason": "Shipping 23 of 25; two prompts need a plan fix." }'reason is required. Accepting a gap is a decision, and it is kept on the order so a short pack is never silent.