Documentation

Job Polling

Long-running image and video generations run asynchronously. You create a job through POST /v1/images/generations, then poll GET /v1/images/generations/:id until it finishes. This page covers the full lifecycle: when async kicks in, how to start a job, how to poll, every response shape, and the errors you can hit.

When a job is created

NavyAI returns a job ID instead of an immediate result in two situations:

  • Video models — Models like veo-3.1, gemini-omni, sora-2, sora-2-pro, kling-2.6, cogvideox-flash, seedance-2.0, wan-2.7, and grok-imagine-video default to async and almost always return a job.
  • `"sync": false` on an image request — Useful when the model is slow, your HTTP client times out, your platform (serverless, browser) cannot hold a long-lived connection, or you want a queue-style background workflow.

Image models default to sync: true and return the image inline. Video models default to async even without sync: false; you can force inline behavior with sync: true only if the upstream provider supports it.

Step 1 — Create the job with sync false

Send a normal image generation request and include "sync": false. The response contains a job ID — store it so you can poll later.

1curl -X POST https://api.navy/v1/images/generations \
2  -H "Authorization: Bearer sk-navy-YOUR_KEY" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "model": "veo-3.1",
6    "prompt": "A drone shot of a coastal city at sunrise, cinematic",
7    "sync": false,
8    "seconds": 6
9  }'

Create-job response

A successful create returns the job in queued state. Persist id — you'll need it to poll.

JSON
1{
2  "id": "job_a1b2c3d4e5f6...",
3  "object": "job",
4  "created_at": 1716112000,
5  "status": "queued",
6  "model": "veo-3.1"
7}

Step 2 — Poll the job

Call GET /v1/images/generations/:id repeatedly with the same API key until status becomes completed or failed. Poll every 3–5 seconds; polling does not count against your token quota.

1curl https://api.navy/v1/images/generations/job_a1b2c3d4e5f6 \
2  -H "Authorization: Bearer sk-navy-YOUR_KEY"

Poll response shapes

While the job is running, the response only contains lifecycle fields:

JSON
1{
2  "id": "job_a1b2c3d4e5f6",
3  "object": "job",
4  "created_at": 1716112000,
5  "status": "in_progress",
6  "model": "veo-3.1"
7}

Once status is completed, result is added. Its shape matches the normal /v1/images/generations response, so the same handler code works for both sync and async images and videos.

JSON
1{
2  "id": "job_a1b2c3d4e5f6",
3  "object": "job",
4  "created_at": 1716112000,
5  "completed_at": 1716112182,
6  "status": "completed",
7  "model": "veo-3.1",
8  "result": {
9    "created": 1716112182,
10    "data": [
11      { "url": "https://s3.api.navy/.../output.mp4" }
12    ]
13  }
14}

If the job fails, error is added and result is omitted.

JSON
1{
2  "id": "job_a1b2c3d4e5f6",
3  "object": "job",
4  "created_at": 1716112000,
5  "status": "failed",
6  "model": "veo-3.1",
7  "error": {
8    "message": "Provider returned an unrecoverable error",
9    "code": "job_failed"
10  }
11}

Status values

  • queued — Accepted and waiting for an available provider slot
  • in_progress — A provider is actively generating
  • completed — Generation finished, output is in result
  • failed — Generation failed, details in error

Errors when polling

  • 404 job_not_found — The job ID does not exist or has expired (jobs are retained for 10 minutes after creation).
  • 403 unauthorized_job_access — The job exists, but you are polling it with a different API key than the one that created it. Jobs are scoped to their creator.

Notes and best practices

  • Persist the job ID immediately. If your client crashes or the user refreshes mid-generation, you can resume polling as long as the job has not expired.
  • Use exponential or fixed-interval polling. 3–5 seconds is a sensible default. Video generation can take up to 10 minutes; image jobs typically finish in 10–60 seconds.
  • Jobs expire 10 minutes after creation. Completed results are not stored long-term — copy result.data[].url to your own storage if you need it past that window.
  • Polling is free. It does not consume tokens or count against your daily quota.
  • Same key only. A job can only be polled by the API key that created it. Server-side proxies must keep the same key for create and poll.
  • No webhooks. NavyAI does not currently push job completion. Polling is the only completion signal.