Guides
Async jobs (polling)
How to track design template and image ad generation — polling and batch polling.
POST /v1/image-ads and POST /v1/design-templates are asynchronous. They return 202 Accepted with the resource in processing and the pipeline runs in the background. This guide covers how to know when it's done.
Status lifecycle
stateDiagram-v2
[*] --> processing: POST returns 202
processing --> completed: outputs ready
processing --> failed: error populated
completed --> [*]
failed --> [*]There are no intermediate states. The progress field updates during processing with pipeline-stage info; that's a UX hint, not a state machine.
You're billed only on completed. Failed jobs do not deduct from your wallet.
Polling
The default. Periodically GET the resource until status changes.
async function waitForCompletion(imageAdId, apiKey) {
while (true) {
const r = await fetch(
`https://api.staticadslab.com/v1/image-ads/${imageAdId}`,
{ headers: { "X-API-Key": apiKey } },
);
const { data } = await r.json();
if (data.status === "completed") return data;
if (data.status === "failed") throw new Error(data.error?.message ?? "failed");
await new Promise((res) => setTimeout(res, 4000));
}
}import time
import requests
def wait_for_completion(image_ad_id: str, api_key: str) -> dict:
while True:
r = requests.get(
f"https://api.staticadslab.com/v1/image-ads/{image_ad_id}",
headers={"X-API-Key": api_key},
)
data = r.json()["data"]
if data["status"] == "completed":
return data
if data["status"] == "failed":
raise Exception(data["error"]["message"])
time.sleep(4)while true; do
RESULT=$(curl -s https://api.staticadslab.com/v1/image-ads/ia_YOUR_ID \
-H "X-API-Key: YOUR_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
echo "Status: $STATUS"
[ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] && break
sleep 4
done
echo "$RESULT" | jq '.data.image_url'Polling tips
- 4 seconds is a good interval for image ads (generation runs ~30–60 seconds).
- 2 seconds works for design templates (faster pipeline).
- Don't poll from the browser. Poll server-side and push updates to clients over your own channel.
- Always cap retries. Add a timeout (e.g. 5 minutes) and throw if exceeded — never poll forever.
Batch polling
When you have many ads in flight, ask for all their statuses in one request:
const ids = ["ia_a", "ia_b", "ia_c"].join(",");
const r = await fetch(`https://api.staticadslab.com/v1/image-ads?ids=${ids}`, {
headers: { "X-API-Key": process.env.SAL_API_KEY },
});
const { data } = await r.json();
const stillProcessing = data.filter((d) => d.status === "processing");This is the right pattern for batch generation. See Batch generation.
Choosing a pattern
| Use this | When |
|---|---|
| Polling | One or a few ads, simple control flow, retries are fine |
| Batch polling | Tens or hundreds of ads in parallel |
Pitfalls
- Don't poll faster than every 2 seconds — you'll hit the rate limit.
- Reading
image_urlwhilestatus === "processing"returnsnull. Wait forcompleted. - A
PATCHon an editable image ad sends the resource back toprocessing. Treat patches as new async jobs.