Async image generation
Synchronous image generation (POST /v1/images/generations) has a 30-second budget. Large resolutions, high step counts, or a saturated deployment hit one of these:
| Response | Meaning |
|---|---|
504 image_generation_timeout | The job didn’t finish inside the 30s sync budget. |
5xx upstream_error | The GPU worker failed — most often out of GPU memory. The sync path can’t always tell you the exact cause. |
429 replica_saturated | Every replica is at its concurrency limit right now. |
The async path solves all three: the request is accepted immediately, runs without the 30s limit, and if it fails you get the exact error code (e.g. vram_exceeded) on the request record.
Submitting an async request
Section titled “Submitting an async request”Add ?async=true to the same images endpoint — same body, same auth. Include an Idempotency-Key header so a network retry can’t create a duplicate job:
curl "https://<your-deployment>.inference.meshive.ai/v1/images/generations?async=true" \ -H "Authorization: Bearer $MESHIVE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order-42-attempt-1" \ -d '{ "model": "<model-id>", "prompt": "A sunset over the ocean, oil painting", "size": "1024x1024", "n": 1 }'import httpx
resp = httpx.post( "https://<your-deployment>.inference.meshive.ai/v1/images/generations", params={"async": "true"}, headers={ "Authorization": f"Bearer {MESHIVE_API_KEY}", "Idempotency-Key": "order-42-attempt-1", }, json={ "model": "<model-id>", "prompt": "A sunset over the ocean, oil painting", "size": "1024x1024", "n": 1, },)job = resp.json() # 202 — {"id": "req_...", "status": "queued", ...}const resp = await fetch( "https://<your-deployment>.inference.meshive.ai/v1/images/generations?async=true", { method: "POST", headers: { "Authorization": `Bearer ${process.env.MESHIVE_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": "order-42-attempt-1", }, body: JSON.stringify({ model: "<model-id>", prompt: "A sunset over the ocean, oil painting", size: "1024x1024", n: 1, }), },);const job = await resp.json(); // 202 — {"id": "req_...", "status": "queued", ...}The response is a 202 Accepted with a request id:
{ "id": "req_9f8e7d6c5b4a3210", "object": "inference.request", "status": "queued", "modality": "image", "estimated_seconds": 30}All request parameters work the same as in sync mode — including the Meshive extensions negative_prompt, seed, steps, guidance_scale, storage_credential_id (output bucket), and webhook_url. See the Images API reference for the full table.
Image edits (/v1/images/edits) accept ?async=true the same way, with one exception: the mask parameter is sync-only (async returns 400 async_mask_unsupported).
Getting the result
Section titled “Getting the result”Three routes — pick whichever fits your integration:
| Route | How | Best for |
|---|---|---|
| Polling | GET /v1/requests/{id} — when status is succeeded, the response includes presigned output_urls | Simple scripts |
| Webhook | Set webhook_url on the request, or register a workspace endpoint | Servers — no polling |
| Console | Requests (status & errors) + Artifacts (the files) | Manual checks |
Polling
Section titled “Polling”curl https://<your-deployment>.inference.meshive.ai/v1/requests/req_9f8e7d6c5b4a3210 \ -H "Authorization: Bearer $MESHIVE_API_KEY"{ "id": "req_9f8e7d6c5b4a3210", "object": "inference.request", "modality": "image", "status": "succeeded", "output_object_key": "serverless/requests/req_9f8e7d6c5b4a3210/result_0.png", "output_bucket": "meshive-r2", "output_urls": ["https://...presigned, valid ~1 hour..."], "error_code": null, "error_message": null, "queued_at": 1780000000, "started_at": 1780000004, "completed_at": 1780000031}Statuses move queued → running → succeeded | failed | canceled. Poll every few seconds until the status is one of the three terminal values — every accepted request is guaranteed to reach one.
Webhook
Section titled “Webhook”Pass webhook_url on the request (or register a workspace-wide endpoint) and Meshive POSTs you a signed event the moment the request finishes — request.completed, request.failed, or request.canceled. Setup, payload schema, and signature verification: Webhooks.
Console
Section titled “Console”Serverless › Requests shows every async request with status and, on failure, the exact error code. Generated files land in Serverless › Artifacts (storage & retention).
When an async request fails
Section titled “When an async request fails”Async failures are classified precisely from the GPU worker, and surface as error_code / error_message on the request (and in the request.failed webhook):
error_code | Meaning | What to do |
|---|---|---|
vram_exceeded | The job exceeded the GPU’s memory | Smaller size/steps, a more quantized model, or raise your price cap so a larger GPU can be assigned |
model_timeout | The model didn’t respond in time (images: 5 min, videos: 30 min) | Retry; if persistent, reduce job size |
pod_crash | The worker ran out of host memory | Contact support |
storage_upload_failed | Result couldn’t be written to your output bucket | Check the storage credential under Settings → Integrations |
Failed and canceled requests don’t add any charge — billing is per GPU-hour of your deployment, not per request.
Canceling
Section titled “Canceling”curl -X POST https://<your-deployment>.inference.meshive.ai/v1/requests/req_.../cancel \ -H "Authorization: Bearer $MESHIVE_API_KEY"- Only
queuedrequests can be canceled —runningmeans the GPU is already working; you get409with the current status. - A successful cancel fires
request.canceledto your webhooks.