Get started · Quickstart

Your first run

Five minutes, four curl commands, one finished image. Everything on this page is a real request against api.esy.com with a real response pasted back — if a command here does not work verbatim, it is a bug in the docs.

Before you start

You need an API key. Create one in os.esy.com under Settings → API keys. The secret is shown once, at creation — Esy stores only a hash of it, so there is no way to recover it later. Put it in your shell:

shellbash
export ESY_API_KEY="esy_sk_…"
A key acts as you
An API key carries the permissions of the account that created it — it is not a reduced-privilege role. Scope it to a single workspace when you create it, and revoke it the moment it leaks. See Authentication.

Step 1 — Start a run

A run is one execution of a workflow. You pick the workflow by its templateId and hand it an intake — the inputs that workflow declares. Here we use generate-illustration, which is public and needs no setup.

POST /v1/runsbash
curl -X POST https://api.esy.com/v1/runs \
  -H "Authorization: Bearer $ESY_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "templateId": "generate-illustration",
    "intake": {
      "prompt": "a lighthouse at dusk, storm rolling in",
      "style": "flat",
      "aspectRatio": "4:3",
      "quality": "low",
      "categories": "landscapes"
    }
  }'

You get 201 back immediately with status pending. Runs execute asynchronously — the API accepts the work and returns; it does not wait for the image.

201 Createdjson
{
  "id": "run-fb0677b2",
  "status": "pending",
  "templateId": "generate-illustration",
  "templateName": "Generate Illustration",
  "currentStepIndex": 0,
  "workflowVersion": "2026.09.09",
  "specVersionHash": "sha256:eb3ced0c91a625e7ad47beaa28f5ff7b6db933ca5f6cac78fb93c1b030852fdb",
  "createdVia": "api_key",
  "queuedAt": "2026-09-13T00:16:58.843436Z"
}

Two fields in that response matter more than they look. workflowVersion and specVersionHash are frozen at creation: this run is pinned to the exact definition that existed the moment you called it, so it stays reproducible even after the workflow is edited. createdVia: "api_key" is provenance — Esy records how every run was started.

Step 2 — Wait for it

Poll the run until it reaches a terminal status.

GET /v1/runs/{run_id}bash
curl -s https://api.esy.com/v1/runs/run-fb0677b2 \
  -H "Authorization: Bearer $ESY_API_KEY"

Terminal statuses are completed, review, failed, and cancelled. Stop polling on any of them. Runs and steps covers the full lifecycle, including the two statuses a human review can produce.

200 OK — about 16 seconds laterjson
{
  "id": "run-fb0677b2",
  "status": "completed",
  "artifactId": "artifact-5a6a9501",
  "durationMs": 16088,
  "totalCosts": {
    "estimatedUsd": 0.007749,
    "actualUsd": 0.007749,
    "currency": "USD",
    "status": "provider_reported"
  }
}
Prefer streaming to polling
For anything user-facing, open GET /v1/runs/{run_id}/events instead. It sends a full snapshot on connect and then every state change as it happens, so you get progress rather than a spinner.

Step 3 — Read the artifact

The run produced an artifact: the durable record of what was made, what it cost, and how it was checked.

GET /v1/artifacts/{artifact_id}bash
curl -s https://api.esy.com/v1/artifacts/artifact-5a6a9501 \
  -H "Authorization: Bearer $ESY_API_KEY"
200 OKjson
{
  "id": "artifact-5a6a9501",
  "runId": "run-fb0677b2",
  "templateId": "generate-illustration",
  "title": "Lighthouse at Dusk with Storm Rolling In",
  "status": "ready",
  "artifactClass": "visual",
  "artifactType": "illustration",
  "version": 1,
  "content": {
    "type": "image",
    "url": "https://images.esy.com/artifacts/illustration/run-fb0677b2/image.webp",
    "mimeType": "image/webp",
    "model": "gpt-image-2.5-sunburst"
  },
  "qa": {
    "status": "pending_review",
    "checks": [
      { "id": "text-gate", "label": "Text gate", "status": "pass", "detail": "" }
    ]
  }
}

content.url is your image, served from images.esy.com. The qa block is the workflow’s own verdict on it — here a text gate that read the image and confirmed it carries no stray lettering.

What it cost

The run above cost $0.0077. Esy itemises that per provider call rather than giving you one opaque number:

StepProviderModelCost
Render illustrationopenaigpt-image-2.5-sunburst$0.004600
Classify assetanthropicclaude-haiku-4-5$0.000884
Text gateanthropicclaude-haiku-4-5$0.002260
storage.uploadcloudflare_r2$0.0000045

Note the render is not even the majority of the bill — the two checks around it cost more than the image did. That is the trade Esy makes on your behalf, and Costs and budgets explains how to cap it.

The whole thing as a script

Start, wait, print the URL. Needs curl and jq.

first-run.shbash
#!/usr/bin/env bash
# Start a run, wait for it, print the artifact URL.
set -euo pipefail

RUN=$(curl -s -X POST https://api.esy.com/v1/runs \
  -H "Authorization: Bearer $ESY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"templateId":"generate-illustration","intake":{"prompt":"a lighthouse at dusk","style":"flat","aspectRatio":"4:3","quality":"low","categories":"landscapes"}}')

ID=$(echo "$RUN" | jq -r .id)
echo "run $ID"

# Poll until the run reaches a terminal status.
while :; do
  sleep 5
  STATUS=$(curl -s "https://api.esy.com/v1/runs/$ID" \
    -H "Authorization: Bearer $ESY_API_KEY" | jq -r .status)
  echo "  $STATUS"
  case "$STATUS" in completed|review|failed|cancelled) break ;; esac
done

ART=$(curl -s "https://api.esy.com/v1/runs/$ID" \
  -H "Authorization: Bearer $ESY_API_KEY" | jq -r .artifactId)

curl -s "https://api.esy.com/v1/artifacts/$ART" \
  -H "Authorization: Bearer $ESY_API_KEY" | jq -r .content.url

Where to go next

If you want to…Read
Understand what just happenedHow Esy works
See every workflow you can runWorkflows and catalog
Know what each intake field meansIntake
Handle failures properlyErrors
Generate hundreds of theseGeneration Orders
In short
  • A run is asynchronous: POST /v1/runs returns pending, and you poll or stream until it is terminal.
  • Every run pins the workflow version it executed, so results stay reproducible after the workflow changes.
  • The artifact carries the output, the QA verdict, and an itemised cost ledger — not just a file.