Gensprite

Jobs and polling

The lifecycle of a generation, and how to wait for one politely.

A job moves through five states, three of them terminal:

queued → running → completed
                 ↘ failed
       (cancel) ↘ cancelled

Creating

POST /v1/jobs charges credits and starts the generation. The charge and the job row are written in one transaction — there is no state in which credits are gone and no job exists.

Idempotency-Key is required on every create. Retry the request with the same key and you get the same job back rather than a second charge; the plugin retries on flaky editor networks for exactly this reason. Quote before you commit with POST /v1/jobs/quote: same body, answers the price, moves nothing.

Polling

GET /v1/jobs/{id} reads our own database and never calls a provider, which is what makes polling cheap enough to be the primary mode rather than a fallback. The response carries an X-Poll-After header — wait that many seconds between asks. Poll until status is terminal.

In a browser there is a push alternative: GET /v1/jobs/{id}/events streams the same job object over server-sent events, one per change. It exists for the web frontend; anything else — the coming Godot plugin and MCP server included — should poll instead.

Failing and refunding

A generation that fails refunds itself. Every movement of credits — charges, purchases, refunds and grants alike — writes exactly one row to the ledger, so the account balance is always the sum of that list and never an independently maintained number that could drift.

Cancelling

POST /v1/jobs/{id}/cancel is accepted while a job is queued or running. A job that already reached a terminal state answers job_not_cancellable.

The files

A completed job carries its output as files, each with a role (which side or frame it is), a url and a content_type. Files expire eventually — files_expired on the job says when they have — but the job itself, its input and its record in the ledger do not. The drawing you put in is kept with the generation, so a second run at different settings never means finding the file again.

On this page