Async jobs & polling
Universal async pattern: submit with mode='async', get a job id back, poll /v1/jobs/:id (or receive a webhook on completion). Same shape across chat, image, and video generation.
Why async
- Long jobs. Reasoning model on a 100K-token corpus, large image batches, video gen. Sync exhausts HTTP timeouts.
- Batch fans. Submit 1000 jobs in 1000 requests, poll in parallel. No connection-holding cost.
- Pipelines. Fire-and-forget with a webhook on terminal status, with no client-side polling at all.
Mode by endpoint
Endpoint Modes supported Default
POST /v1/chat/completions sync · stream · async sync
POST /v1/images/generations sync · async sync
POST /v1/videos/generations async (only) async
(sync would always
time out; gen takes
10–60s wall-clock)Submit + poll
# Submit async
JOB_ID=$(curl https://api.genie.tech/v1/chat/completions \
-H "Authorization: Bearer $GENIE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"mode":"async","model":"qwen3:14b","messages":[...]}' \
| jq -r .id)
# Poll until terminal
while true; do
STATUS=$(curl -s "https://api.genie.tech/v1/jobs/${JOB_ID#chatcmpl-}" \
-H "Authorization: Bearer $GENIE_API_KEY" | jq -r .status)
case "$STATUS" in
completed) echo "done"; break ;;
failed) echo "failed"; exit 1 ;;
*) sleep 2 ;;
esac
doneAsync response shape
Every async submission returns 202 with the same shape:
{
"id": "chatcmpl-cmoz...",
"object": "chat.completion.async",
"status": "queued",
"polling_url": "/api/v1/jobs/cmoz...",
"created": 1731020000
}Job poll endpoint
GET /v1/jobs/:id returns the job's current status + result if terminal:
{
"id": "chatcmpl-cmoz...",
"status": "completed",
"result": {
"id": "chatcmpl-cmoz...",
"object": "chat.completion",
"choices": [{ "message": { "role": "assistant", "content": "..." } }],
"usage": { "prompt_tokens": 12, "completion_tokens": 28, "total_tokens": 40 }
}
}Status values: queued · running · completed · failed · cancelled · timeout.
Webhook delivery
Supply webhook: { url, secret } in the submit body and Genie POSTs the completed-job body to your URL when it hits a terminal state. Signed with HMAC-SHA256 inX-Genie-Signature. See Webhooks.
Idempotency. The job id is stable across retries. If your client crashes mid-poll, resume by calling
GET /v1/jobs/:id with the same id: no duplicate billing, no duplicate work.