Skip to main content

States

Every request progresses through one of these statuses:
COMPLETED, FAILED, and CANCELLED are terminal — the request will never transition away from them.
Two things about terminal states that are easy to get wrong:A failed generation is recorded as COMPLETED, not FAILED. When the provider errors, the request itself completed — it just produced no output — so it lands on COMPLETED with a populated error and a billingStatus of failed. FAILED is reserved for requests the platform force-fails after they get stuck. So status alone does not tell you whether the work succeeded; check billingStatus (charged or partial means real output).CANCELLED applies to deployment jobs only. For catalog models and wrappers nothing sets it, and cancel_url does not cancel (see Cancellation). Jobs submitted to your own Serverless GPU deployment can reach it — so a poller shared across both must treat CANCELLED as terminal.

Submitting a request

The response returns immediately with request_id, status: "IN_QUEUE", and three URLs:

Tagging requests with metadata

The submit body may include a reserved top-level metadata object alongside the model’s input fields — a flat string map of your own tags (job ids, environments, batch labels):
Metadata is stored on the request and returned whenever you read the request back — GET /requests/{requestId}, the response_url result payload, and list items. (The lightweight status_url envelope does not include it.) It is never sent to the model and never merged into the stored input. Limits (violations return 400): Filter your request history by metadata with a single URL-encoded JSON query param — pairs match exactly and are AND-ed, combinable with status, modelEndpoint, and pagination:
metadata is a reserved word at the top level of the submit body: a model whose own input schema defines a metadata field cannot receive it through the raw body.

Three ways to watch a request

GET /{ownerName}/{modelName}/requests/{requestId}/status returns the same response shape as the create call. Poll at 1–2 second intervals. The SDK helpers (subscribe in JS, submit_async + iter_events in Python) wrap this loop for you.
The queue_position field is currently always 0 — real queue depth is not tracked. Don’t surface it as “you’re #N in line” in your UI.

Cancellation

PUT (or GET) /{ownerName}/{modelName}/requests/{requestId}/cancel — what it does depends on what the endpoint is. On a Serverless GPU deployment, cancel is real. The job is stopped, the request lands on terminal CANCELLED with billingStatus: "failed", and a completed webhook fires. See Cancel and terminal states.
On a catalog model or wrapper, this endpoint does not cancel anything. It is wired to the same handler as status_url and returns the same response, so the request continues to run and will still be billed if it completes.The route exists so that clients and SDKs built against it keep working once real cancellation ships for catalog models too. Until then, treat a submitted model request as uninterruptible and do not rely on cancel_url to stop billable work.

Platform safety net: automatic finalization

You do not need to implement retry logic for requests you’ve abandoned. A background sweep runs every 60 seconds and re-checks every request that is:
  • Still IN_PROGRESS past the provider’s expected duration, or
  • Marked COMPLETED by the provider but missing output media (media upload still in flight).
The sweep advances each row through its terminal state automatically (uploads media to S3, generates thumbnails, charges billing on success, or marks failed otherwise). A request that has been retried 5 times and is older than 6 hours is force-failed. After that point its status is permanently FAILED and any associated billing is reverted.
Concretely: if your client crashes between submitting a request and polling for its result, the platform will still finalize the request correctly. You can retrieve it later with GET /requests/{requestId} (no model path required) or via list_my_requests.

Billing tie-in

Billing settles on the same lifecycle:
  • A request transitioning to COMPLETED charges the user’s balance.
  • A request transitioning to FAILED or CANCELLED is not charged.
  • A request that completed at the provider but failed schema validation is recorded with billingStatus: "failed" — you are not billed, but the call returns 422 so you can surface the upstream error.
See errors for the 422 payload shape.