Tasks
GET /api/v1/tasks/{id} reference — universal task polling for image, video, and audio generation.
Generation on reAPI is asynchronous. Every submission endpoint —
/api/v1/images/generations, /api/v1/videos/generations, and any future
/api/v1/audio/generations — returns a task id, and you poll
GET /api/v1/tasks/{id} until the task reaches a terminal state.
This page is the canonical reference for the polling endpoint. The
request shape, status values, error codes, polling cadence, and refund
semantics are the same regardless of which submission endpoint produced
the task; only the contents of output differ by media kind.
GET /api/v1/tasks/{id}
Retrieve the current state of a task.
Request
GET /api/v1/tasks/{id}
Authorization: Bearer rk_live_xxx{id} is the id returned by the submitting POST. Polling does not
consume credits.
For exact GPT Image token evidence, opt in without changing the legacy polling response used by existing clients:
GET /api/v1/tasks/{id}?include=billing
Authorization: Bearer rk_live_xxxPrefer not to poll at all? Pass a webhook_url when you submit and reAPI
POSTs this same response to you when the task finishes — see
Webhooks. This endpoint stays the guaranteed path: if
a webhook delivery fails, the result is still here, and
?include=webhook returns the delivery record so you can see what
happened.
Response
200 OK — image task example:
{
"id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
"model": "gpt-image-2",
"status": "completed",
"created_at": 1735000000,
"output": {
"image_urls": [
"https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png",
"https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/1.png"
]
},
"usage": { "credits": 56 },
"error": null
}200 OK — video task example:
{
"id": "task_01k9s419324drezfbwnsvxyr6h",
"model": "doubao-seedance-2.0",
"status": "completed",
"created_at": 1762853430,
"output": {
"video_urls": [
"https://cdn.reapi.ai/media/tasks/01k9s419324drezfbwnsvxyr6h/0.mp4"
]
},
"usage": { "credits": 189 },
"error": null
}usage
Backward-compatible whole-credit settlement summary.
"usage": { "credits": 189 }usage is always present and credits is always an integer, in every state, so
a polling client can read usage.credits without guarding the access.
This legacy wire type is unchanged for existing generated clients.
| State | usage.credits |
|---|---|
processing | 0 — nothing settled yet |
completed | the amount charged |
failed | 0 — fully refunded (or the amount kept, if any) |
0 appears in two different situations, so pair it with status:
processing + 0 means the task has not been billed yet, while failed + 0
means it was billed and refunded.
This is the rounded-up settled summary, not the reservation. Submitting a request places a hold based on the parameters you sent. Once the task settles, the reservation is replaced by the final amount: excess reserve is returned, while an amount above the reserve is deducted from the remaining balance.
How far the two diverge is model-specific. The cases below are examples, not universal behaviour — check the model's own page for its billing table:
- Seedance 2.5 with
duration: -1holds the 30-second ceiling and then settles against the video actually produced. - Wan 3.0 with
duration: -1is charged at the 30-second ceiling. The length the model picks does not bring it down, so pass an explicitdurationwhen cost matters. - Reference-video jobs, on the models that accept them, bill input seconds plus output seconds, and some tiers bill a minimum window — a short clip can settle above its literal duration.
For legacy integer-priced models, read usage.credits instead of recomputing
any of this client-side. Token-metered models additionally expose their
settlement source under billing.
For gpt-image-2-official, polling with ?include=billing adds a top-level
billing object with the exact image-token meters and settled amount. Without
that query parameter, the response keeps the legacy field set exactly:
"usage": { "credits": 39 },
"billing": {
"source": "openai_token_usage",
"credits_exact": 38.966,
"cost_usd": 0.038966,
"text_input_tokens": 396,
"image_input_tokens": 2482,
"image_output_tokens": 571
}The submitted request reserves the Playground/model-page estimate. A successful task replaces it with:
actual_usd =
text_input_tokens x $5 / 1,000,000
+ image_input_tokens x $8 / 1,000,000
+ image_output_tokens x $30 / 1,000,000
actual_micro_usd =
text_input_tokens x 5
+ image_input_tokens x 8
+ image_output_tokens x 30
final_micro_usd =
ceil(actual_micro_usd x factor_basis_points / 10,000)
billing.cost_usd = final_micro_usd / 1,000,000
billing.credits_exact = final_micro_usd / 1,000
charged_micro_usd = final_micro_usd - shortfall_micro_usd
usage.credits = ceil(charged_micro_usd / 1,000)The balance and public billing values retain final_micro_usd precision; the
factor is rounded upward only once at that boundary. usage.credits remains
the rounded-up whole-credit compatibility field; do not use it to reconcile
token-metered tasks. Use billing.credits_exact or billing.cost_usd.
If a successful generation does not return all three trustworthy usage meters,
the task still completes and the admission reservation becomes the final
whole-credit charge. With ?include=billing, that fallback is explicit and
never presented as exact:
"usage": { "credits": 56 },
"billing": {
"source": "reservation_estimate",
"credits_charged": 56,
"cost_usd_charged": 0.056
}Only source: "openai_token_usage" carries formula-derived exact token fields.
In the rare case that the actual amount exceeds both the reservation and the
remaining balance, the successful task still completes and the balance is
reduced to zero. reAPI records the unpaid remainder internally as a billing
shortfall; billing.credits_exact and billing.cost_usd continue to report the
full formula-derived actual amount, while usage.credits remains the rounded
whole-credit summary of the amount actually collected.
Status values
| Status | Meaning |
|---|---|
processing | Submitted, provider is generating |
completed | Done — output populated |
failed | error populated; usage.credits shows whether the reservation was refunded or a post-generation charge was retained |
Output shape
The shape of output depends on the media kind of the task:
| Media kind | Field | Type |
|---|---|---|
| Image | image_urls | string[] |
| Video | video_urls | string[] |
| Audio | audio_urls | string[] |
Some video models add an extra last_frame_url (string) when the request
opted into a return-last-frame capability.
URLs returned in output are rehosted to reAPI's CDN. If you need
long-term archival, copy them to your own storage as soon as the task
completes — bucket lifecycle policies are configured per-deployment and
not guaranteed by this contract.
Errors
| HTTP | code | When |
|---|---|---|
| 401 | 10001 – 10005 | Auth missing / invalid / revoked |
| 404 | 40001 | Task doesn't exist or belongs to another user |
| 429 | 50001 | Per-user request rate limit exceeded — retry after Retry-After seconds |
Polling pattern
Recommended:
attempt 1: wait 2s
attempt 2: wait 2s
...
the worker keeps a task alive up to a wall-clock cap before it self-reports
an 80002 timeout: 1 hour for image and audio, 48 hours for video. Most tasks
finish far sooner (image/audio usually under a minute, video in minutes), so
size your client-side give-up to your own tolerance, not the cap.The polling endpoint is cached for 5 seconds while a task is in-flight, so polling faster than every 2–3 seconds returns the same state and just consumes rate-limit budget. Video tasks routinely take several minutes; pace your polling accordingly.
Refund behavior
Provider failures, timeouts, and persistence failures are automatically refunded by the worker when the workflow ends. Missing token evidence after a successful GPT Image generation is not a task failure: the image is delivered and the reserved amount is charged. Any credit return happens atomically with the status flip, before a poll observes it, and re-polling never refunds twice.
Some model-specific post-generation safety policies can retain the generation
charge even though the output is hidden and the task status is failed. Always
read usage.credits: failed + 0 means fully refunded, while a positive
value is the retained amount documented by that model.
A failed task surfaces the failure code under error:
{
"id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
"status": "failed",
"output": null,
"error": {
"code": 80006,
"message": "Request violates content policy"
}
}The code here is one of the 8xxxx workflow-execution codes — see
Errors → 8xxxx.