Job Polling
Direct generation and publishing operations follow a create-then-poll pattern.
How it works
- Submit a request, such as
POST /image/generateorPOST /publish/instagram. - Poll
GET /jobs/inference/{inferenceJobId}orGET /jobs/publish/{outputJobId}until the job reaches a terminal status. - Read output media or publish details from the completed job response.
GET
/api/v1/jobs/inference/{inferenceJobId}GET
/api/v1/jobs/publish/{outputJobId}Local CLI editing does not create a public API job. The wonda edit commands render locally and return a mediaId or downloaded file path when the render completes.
Status values
| Status | Terminal | Description |
|---|---|---|
idle | No | Job is queued and waiting to start. |
locked | No | Job has been claimed by a worker. |
in_progress | No | Job is actively running. |
queued | No | Publish job is waiting in queue. |
succeeded | Yes | Job completed successfully. |
failed | Yes | Job encountered an error. |
canceled | Yes | Inference job was canceled. |
Polling strategy
Start polling at 1-second intervals. For long-running jobs such as video generation, increase the interval up to 5 seconds to reduce unnecessary requests.
Chaining pattern
A typical workflow chains async API work with local CLI editing:
upload -> generate -> poll -> take output mediaId -> edit locally with wonda CLI -> publish -> pollFull flow example
const BASE = "https://api.wondercat.ai/api/v1";
const HEADERS = {
Authorization: "Bearer sk_your_api_key_here",
"Content-Type": "application/json",
};
async function pollJob(type, id) {
let delay = 1000;
while (true) {
const job = await fetch(`${BASE}/jobs/${type}/${id}`, {
headers: { Authorization: HEADERS.Authorization },
}).then((response) => response.json());
if (job.status === "succeeded") return job;
if (job.status === "failed") {
throw new Error(job.errorMessage ?? "Job failed");
}
if (job.status === "canceled") {
throw new Error("Job was canceled");
}
await new Promise((resolve) => setTimeout(resolve, delay));
delay = Math.min(delay * 1.5, 5000);
}
}
const generation = await fetch(`${BASE}/image/generate`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
model: "nano-banana-2",
prompt: "A sunset over the ocean",
params: { resolution: "2K" },
}),
}).then((response) => response.json());
const generationResult = await pollJob("inference", generation.inferenceJobId);
const generated = generationResult.outputs.find(
(output) => output.media,
)?.media;
if (!generated?.mediaId) {
throw new Error("No generated media found");
}
const publish = await fetch(`${BASE}/publish/instagram`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
mediaId: generated.mediaId,
instagramAccountId: "550e8400-e29b-41d4-a716-446655440000",
caption: "Made with Wonda",
product: "IMAGE",
}),
}).then((response) => response.json());
const publishResult = await pollJob("publish", publish.outputJobId);
(() => {})("Publish status:", publishResult.status);