Get results
A task runs in the background. Poll it or receive a webhook, then download each output with a short-lived link.
Task lifecycle
A create returns HTTP 202 with the task's id. Its status is processing from then until it closes:
status | Meaning | Open |
|---|---|---|
processing | Accepted and not finished: the Credits hold is placed, the model works on it and the output is stored for download. | Yes |
succeeded | Done. result lists the outputs. | No |
failed | Closed without a result. error.code says why. | No |
canceled | The system closed it before it started, for example because it was not funded or no model capacity freed up in time. Nothing is charged. | No |
unresolved | Still unfinished at its deadline, execution_expires_after (24 hours by default; Seedance allows 1–72 hours). The hold is released and nothing is charged; treat it as failed. If the result arrives later, late_result_available becomes true and result is filled at no charge, with the webhook event generation.late_result_available. | No |
execution_status follows the same rule: processing until the model run ends. billing_status and delivery_status show funding and storage separately: billing_status is pending until Credits are held. Older releases listed the steps inside processing (pending_funding, queued, submitting, submission_unknown, running, pending_investigation, finalizing) as statuses; the list filter still accepts those names and treats each as processing.
A task is closed once closed_at is set. Only a closed task has its final status, result and price.charged.
Poll
Read the task with get a generation every 5 to 10 seconds until closed_at is set.
Python
import os, time, requests
api = "https://api.vizoapi.com/v1"
headers = {"Authorization": f"Bearer {os.environ['VIZO_API_KEY']}"}
def wait(task_id):
while True:
task = requests.get(f"{api}/generations/{task_id}", headers=headers, timeout=30).json()
if task["closed_at"]:
return task
time.sleep(5)Node.js
const api = "https://api.vizoapi.com/v1";
const headers = { Authorization: `Bearer ${process.env.VIZO_API_KEY}` };
export async function wait(taskId) {
for (;;) {
const task = await fetch(`${api}/generations/${taskId}`, { headers }).then((r) => r.json());
if (task.closed_at) return task;
await new Promise((r) => setTimeout(r, 5000));
}
}Or receive a webhook
Pass webhook_endpoint_id on the create to get a signed POST when the task closes. Treat the webhook as a signal and read the task again for the full result. See Webhooks.
Download the outputs
result.outputs lists each output with its asset_id, in order. A video model may also return result.last_frame_asset_id when you asked for the last frame. Request a download link for each asset with download an asset, then fetch the file before url_expires_at.
URL=$(curl -fsS https://api.vizoapi.com/v1/assets/$ASSET_ID/download \
-H "Authorization: Bearer $VIZO_API_KEY" | jq -r .url)
curl -fsS -o output.mp4 "$URL"Outputs are kept for 7 days after they are created. Store the files you want to keep on your side.
Canceling
A task cannot be canceled through the API. Once accepted it runs to its end, and it is charged only if it succeeds. Stopping your polling does not stop it. Only the system cancels a task, before it starts; the task then closes as canceled, its hold is released and a generation.canceled event is sent. allowed_actions is always empty.
Late results
If the model delivers after the task has already closed without a result, the task gets late_result_available: true and a result, and a generation.late_result_available event is sent. Downloading a late result is free; the task's charge does not change.