Track progress
PollGET /v1/jobs/{job_id}?include_result=true every 30–60 seconds. Save the job ID returned at acceptance. Stop polling when job.status is succeeded, failed, or cancelled. Inspect job.error on failure. For batches, poll the batch and paginate its items rather than polling every job.
Cancel a job
Retry generation safely
Give each intended generation a uniqueIdempotency-Key (1–128 ASCII letters,
digits, dots, underscores, colons or hyphens):
Idempotency-Replayed: true. A different body
with the same key returns 409 idempotency_key_reused for Personal keys or
409 idempotency_conflict for Team keys. For Personal requests, concurrent or interrupted
acceptance returns 409 request_in_progress with Retry-After: 5; retry the same
key. If that persists, contact support with X-Request-ID rather than creating a
new key and risking a duplicate job. Keys are scoped to your account and API deployment, and currently retained
without automatic expiry. Recorded 4xx responses are replayed too; after correcting
such a request, use a new key. Personal requests without a key create a new job each time; Team requests without a key are rejected.
The 202 response includes Location: /v1/jobs/{id} and Retry-After: 30.
Completion notifications
Generation continues on the server when your client disconnects. Save thejob_id to check the result later; you do not need to keep sending requests to keep generation running.
Use polling every 30–60 seconds for all account scopes. Personal-key clients can alternatively keep one SSE connection for progress and completion; Team SSE currently returns the restriction described above. The API does not provide webhooks or a guaranteed completion email. Any account email notifications are supplementary; use the job status or SSE done event to drive your integration.
Streaming progress
SSE delivers a sequence of server events over one HTTP response, including progress and the terminaldone event. It avoids repeated status requests. The currently
deployed handler supports personal jobs; Team jobs must use polling until
Team event-store integration is available.
sequence number. Reconnect with ?after=LAST_SEQUENCE to receive later events. Progress event types can vary; ignore types your client does not recognize. ping is a keepalive. done includes the terminal status and job_id, and closes the stream. Fetch the job with include_result=true to retrieve the asset after success.
Retry export without regeneration
If Blender authoring already succeeded and only export failed, this generation retry returns409 export_retry_required. Use the saved-artifact recovery endpoint:
202 with a new job_id and Location.
Poll that job and use its new asset_id for downloads. The original job, batch
counts and artifacts remain unchanged. retry_of_job_id identifies the previous
job and retry_mode is export. When known, failure_stage distinguishes
blender, export, and parent failures.
Recovery requires successful saved authoring, stopped workers, settled prior
charges and an available authoring ZIP. It uses the original pinned release,
not whichever exporter was most recently deployed. Retain that release’s worker
app. Recovery cannot start Blender authoring or paid model/image calls. USD is
exported again and original GLB bytes are retained. Extra formats, if configured,
follow that original release’s export policy. Geometry,
physics, joints and materials are reused; only the library record ID changes for
the new result. This operation is not geometry repair or physics validation.
Normal Team capacity and its configured billing policy still apply. Do not
assume a successful export retry is free or that every policy creates a credit
hold. Modal compute costs remain separate from customer pricing. Reuse the same
idempotency key after a lost response. If this recovery also fails, its job can be
passed to retry-export again; saved-authoring lineage remains tied to the
original source.