Task commitment and retry
Why an accepted generation task cannot be canceled, and how failed or expired tasks are retried safely.
Once createTask is accepted, the generation task is committed and cannot be canceled. This rule applies while it is queued as well as while it is running: generation cannot be reliably stopped once it has started, so SpicyAPI never exposes a local action that could report cancellation while the work — and its cost — carries on.
Accepted tasks are irreversible
Review the model, inputs and estimated charge before submitting. Closing the browser, leaving the page or deleting an API key does not stop an accepted task.
Retry a terminal task
A retry runs a finished, unsuccessful task again: it creates a new task with the same model, input and callback URL, so you do not have to send the original request body again. The new task is billed like any other: its estimated charge is held when it is accepted, and it is charged only if it succeeds.
POST /api/v1/jobs/retrycurl -X POST https://api.spicyapi.ai/api/v1/jobs/retry \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: retry-order-8814-1" \
-d '{"taskId":"job_01k3m8x9q2z4v7n5p6r8s0t1w3"}'Replace the example taskId with the ID of your failed task. Always send an Idempotency-Key with retry (for example retry-<sourceTaskId>-1): without one, a double click or a network retry creates two billed tasks.
Only failed and expired tasks should be retried. Historical canceled records remain readable and may also be retried for backward compatibility, but new tasks cannot enter that state through a user action. Success creates a new queued task and returns HTTP 200 (not 202 as createTask does), with code: 200:
{
"code": 200,
"msg": "success",
"data": {
"taskId": "job_01k3mnewtask",
"sourceTaskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
"state": "queued",
"estimatedCost": "0.08",
"deadlineAt": "2026-08-28T10:12:04Z"
},
"request_id": "req_01k3mretry"
}Poll or wait for the new taskId, not the source one; see Asynchronous tasks.
- The source task remains terminal and unchanged.
- The new task's
sourceTaskIdpoints to the source, preserving retry lineage. - Current schema, price, permission and balance checks run again. A retry is a new task: it is queued again and processed independently of the source.
- The new task sends its callback to the same
callBackUrlas the source task, and keeps the source task's retention period; anX-Spicy-Retentionheader onretryis ignored. - A retry reuses the source task's
inputexactly. Reference files uploaded to SpicyAPI — including small Base64 images, which are stored as uploads — last one day. After that, a retry returns400: upload the file again and create a new task withcreateTask. Idempotency-Keyis scoped to the source task and retry action. Repeating the same key for the same source task returns the same new task instead of creating another.
When retry is refused
Nothing is held or charged when retry returns an error.
| Response | Why | What to do |
|---|---|---|
404 | The source task does not exist, or was created with a different API key | Retry with the key that created it |
409 | The source task succeeded (a new generation needs createTask), is still queued or running, or its billing is not final yet | Wait until it is failed or expired with settled: true; for another generation use createTask |
409 | The source task's input is no longer stored — its prompt retention period passed, or you destroyed its content | Send the original request again with createTask |
400 | A referenced upload has expired, or the callback URL saved on the source task no longer passes validation | Upload the file again, or use a valid callBackUrl, and send the request with createTask |
402 | Not enough balance, or a spend cap was reached | See Billing |
A network error is not a failed task
If a createTask connection breaks before the response arrives, replay createTask with its original Idempotency-Key. Use retry only when an existing task has a confirmed terminal state.
State and retry matrix
| Current state | What you can do |
|---|---|
queued / running | Wait for the terminal result; the task cannot be canceled |
succeeded | Read or download the result; create a new task for another generation |
failed / expired | Retry to create a separately billed task |
historical canceled | Read the record or retry it; no new user cancellation is available |
Before retrying, look at errorCode. rate_limited, upstream_unavailable and upstream_failed are worth a retry; timeout and generation_failed may fail the same way again. For invalid_request, unsupported_combination and content_rejected the same input will fail again, and for invalid_asset the reference file has to be uploaded again — change the input and use createTask instead. See Task failure codes.

