# Create a generation

`createGeneration`

`POST /v1/generations`

Each accepted POST durably records a separate generation. The response has status processing and billing_status pending; the reserved amount is zero until Credits are held. A funding rejection closes the task with error.code set; read it again to see it. Submitting the same request twice can incur two charges. After a lost response, check the generation list before deciding to create another task. HTTP 429 with code concurrency_limited means the organization already has as many unfinished tasks of this media type (video, image, audio or other) as its concurrency limit allows (by default 3 video, 10 image and 10 audio tasks at once per organization; see /docs/rate-limits); nothing is recorded or held, so retry after the Retry-After seconds or queue on your side. Other 429 answers use rate_limited.

## Authentication

Send your project key in the request header, for example `Authorization: Bearer $VIZO_API_KEY`. Keep the key on your server.

## Request body

- `input` (object, Required) The model input. Its schema is the model's inputSchema in the catalog.
- `metadata` (map<string, string>, Optional) Your own string values, returned unchanged. Put client_reference here so a lost response can be matched later.
- `model` (string, Required) Model ID from listModels or the model page. At least 1 characters
- `webhook_endpoint_id` (string, Optional) Webhook endpoint to notify when the task changes state. Create endpoints in the console.

```json
{
  "model": "seedance-2-5",
  "input": {
    "content": [
      {
        "type": "text",
        "text": "A paper boat drifting on a pond"
      }
    ],
    "resolution": "720p",
    "duration": 5
  }
}
```

## Responses

### 202 Accepted

- `allowed_actions` (string[], Required, can be null) Actions you can take now, such as cancel. Rely on this list instead of inferring from the status.
- `billing_closed_at` (date-time, Optional) When the hold was settled or released; absent while Credits are still held.
- `billing_status` (string, Required) Pending awaits funding; unfunded closed without a hold; held means Credits are held for the task; settled charges verified delivery at the existing pricing rules; released returns the hold after failure, cancellation, timeout or zero-charge delivery; refunded reverses previously consumed generation Credits. Allowed values: `pending`, `unfunded`, `held`, `settled`, `released`, `refunded`
- `closed_at` (date-time, Required, can be null) When the task closed. Stop polling once it is not null.
- `created_at` (date-time, Required) When the generation was accepted. Lists are ordered by this time, newest first.
- `customer_resolution_deadline` (date-time, Required) Twenty-four hours after acceptance. Holds still unsettled at this time are released.
- `delivery_status` (string, Required) Output delivery: pending before upstream success; copying into managed storage; ready after verified delivery; failed when delivery cannot complete. Allowed values: `pending`, `copying`, `ready`, `failed`
- `error` (object, Required, can be null) Set when the task closed without a result. Read error.code.
  - `code` (string, Required) Funding: insufficient_balance, balance_negative (Credits were owed when the task came to be funded), budget_exceeded or spending_blocked; recovery_review when recovery closes an unfunded task for manual reconciliation. Provider: provider_unavailable after capacity/recovery exhaustion; input/output_moderated for safety refusal; input_media_invalid or input_media_unreachable for media refusal; draft_expired for an expired draft; input_rejected for unsupported input; delivery_failed when the provider succeeded but the output could not be stored; generation_failed for other terminal provider failures. Failed tasks release their customer hold. Allowed values: `insufficient_balance`, `balance_negative`, `budget_exceeded`, `spending_blocked`, `recovery_review`, `provider_unavailable`, `input_moderated`, `output_moderated`, `input_media_invalid`, `input_media_unreachable`, `draft_expired`, `input_rejected`, `delivery_failed`, `generation_failed`
- `execution_status` (string, Required) Supplier execution state, separate from delivery and billing: processing until execution ends. Succeeded means upstream execution finished, not that output delivery is ready. Allowed values: `processing`, `succeeded`, `failed`, `canceled`, `unresolved`
- `held_at` (date-time, Optional) When Credits were held for the task; absent while it awaits funding or when it closed unfunded.
- `id` (string, Required) Resource ID. Save it as soon as you receive it.
- `input` (any, Optional) The model input as accepted, after normalization, with media as sent: asset ids or your own URLs. Returned when reading a single task; list entries omit it.
- `key_id` (string, Optional) API key that created the task; empty for console tasks.
- `key_name` (string, Optional)
- `late_result_available` (boolean, Required) A result that arrived after closing is provided at no charge.
- `metadata` (map<string, string>, Optional) Your own string values, returned unchanged. Put client_reference here so a lost response can be matched later.
- `model` (string, Required) Public model id the generation was created with.
- `price` (object, Required) Credits for this task: estimated (the estimate, which is the amount held; the charge follows actual usage and may differ slightly), reserved (held right now), charged (actual usage at the fixed rate, 0.000 until settlement) and refunded (returned by a refund).
  - `charged` (string, Required) Credits consumed by this task. Set when billing_status is settled: the actual usage the model reported at the fixed rate, which may be above or below estimated; any unused part of the hold returns to the balance, and usage above the hold is charged too. 0.000 in every other state, including after a refund.
  - `estimated` (string, Required) The estimated cost of this task, in Credits, fixed when the task was accepted. This is the amount held for the task. The charge follows actual usage and may differ slightly from it, above or below.
  - `refunded` (string, Required) Credits a refund returned to the balance: what this task had been charged. 0.000 unless billing_status is refunded.
  - `reserved` (string, Required) Credits held for this task right now, as a decimal string with 3 places. Equal to estimated while billing_status is held, otherwise 0.000.
  - `unit` (string, Required) Every amount is in Credits. Allowed values: `credit`
- `queue_ms` (integer, Optional) Milliseconds from acceptance to first dispatch.
- `result` (object, Required, can be null) Delivered assets, once available.
  - `asset_id` (string, Optional)
  - `last_frame_asset_id` (string, Optional)
  - `metadata` (object, Optional)
    - `duration` (integer, Optional)
    - `frames` (integer, Optional)
    - `framespersecond` (integer, Optional)
    - `generate_audio` (boolean, Optional)
    - `ratio` (string, Optional)
    - `resolution` (string, Optional)
    - `seed` (integer, Optional)
  - `outputs` (object[], Optional, can be null)
    - `asset_id` (string, Required)
    - `content_type` (string, Required)
    - `index` (integer, Required)
  - `voice_id` (string, Optional)
- `run_ms` (integer, Optional) Milliseconds from first dispatch to close.
- `source` (string, Required) Where the generation was created: api (API key) or console (signed-in session). Allowed values: `api`, `console`
- `started_at` (date-time, Optional) When the task was first dispatched to run.
- `status` (string, Required) processing from acceptance until the task closes, including while it awaits funding and while outputs are copied; succeeded has delivered outputs; failed, canceled and unresolved are closed. Canceled is set by the system only, for example when a task is not funded or not started in time. Unresolved closes after the resolution deadline. A late result may still arrive without a new charge. Allowed values: `processing`, `succeeded`, `failed`, `canceled`, `unresolved`
- `version` (integer, Required)

```json
{
  "allowed_actions": [],
  "billing_closed_at": "2026-11-02T08:00:00Z",
  "billing_status": "held",
  "closed_at": null,
  "created_at": "2026-11-02T08:01:43Z",
  "customer_resolution_deadline": "2026-11-03T08:00:12Z",
  "delivery_status": "pending",
  "error": null,
  "execution_status": "processing",
  "held_at": "2026-11-02T08:00:00Z",
  "id": "gen_01JD8Z5QW3XR",
  "input": {},
  "key_id": "string",
  "key_name": "string",
  "late_result_available": false,
  "metadata": {
    "client_reference": "order-1042"
  },
  "model": "MODEL_ID",
  "price": {
    "charged": "0.000",
    "estimated": "157.000",
    "refunded": "0.000",
    "reserved": "157.000",
    "unit": "credit"
  },
  "queue_ms": 1,
  "result": null,
  "run_ms": 1,
  "source": "api",
  "started_at": "2026-11-02T08:00:00Z",
  "status": "processing",
  "version": 1
}
```

### 401 Unauthorized

```json
{
  "error": {
    "code": "invalid_credentials",
    "message": "API key is missing, malformed, expired or revoked.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 402 Payment Required

```json
{
  "error": {
    "code": "insufficient_balance",
    "message": "Available credits cannot cover the hold.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 403 Forbidden

```json
{
  "error": {
    "code": "scope_denied",
    "message": "The key does not allow this operation for this project.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 404 Not Found

```json
{
  "error": {
    "code": "resource_not_found",
    "message": "The resource is not available to this project.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 409 Conflict

```json
{
  "error": {
    "code": "conflict",
    "message": "The request conflicts with the current state of the resource.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 422 Unprocessable Entity

```json
{
  "error": {
    "code": "invalid_input",
    "message": "Input does not match the published schema.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 429 Too many requests. Code concurrency_limited: the organization already has as many unfinished tasks of this media type as its concurrency limit allows, by default 3 video tasks at once per organization (see /docs/rate-limits); nothing is recorded or held. Code rate_limited: the per-minute rate or the queued-task backlog is full. Retry after Retry-After seconds.

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Check Retry-After.",
    "retryable": true,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 500 Internal Server Error

```json
{
  "error": {
    "code": "request_failed",
    "message": "The request failed. Check recent generations before submitting again.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 503 Service Unavailable

```json
{
  "error": {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable.",
    "retryable": true,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

## Errors

Errors share one body. Include the request_id when you contact support.

### Error body

- `error` (object, Required) Details of the error.
  - `code` (string, Required) Stable request error code. invalid_input rejects the request schema; invalid_credentials/scope_denied reject authentication/authorization; ip_not_allowed/model_not_allowed reject API key IP/model restrictions; resource_not_found hides missing or inaccessible resources; conflict rejects incompatible state; insufficient_balance/budget_exceeded/spending_blocked reject funding; balance_negative (402) refuses new tasks while the organization owes Credits from a charge above its hold, until a top-up repays them; rate_limited/concurrency_limited ask for a later retry; temporarily_unavailable is transient service capacity; request_failed covers other HTTP failures. tier_not_sold, draft_not_found, draft_expired and input_duration_out_of_range reject model-specific input. input_media_invalid rejects a detected format/type mismatch; input_media_too_large rejects a probed byte size above the model limit. storage_quota_exceeded rejects an upload when the organization's storage is full. See errors for field-level details. Allowed values: `invalid_input`, `invalid_credentials`, `insufficient_balance`, `balance_negative`, `scope_denied`, `resource_not_found`, `conflict`, `rate_limited`, `concurrency_limited`, `temporarily_unavailable`, `request_failed`, `ip_not_allowed`, `model_not_allowed`, `tier_not_sold`, `draft_not_found`, `draft_expired`, `input_duration_out_of_range`, `input_media_invalid`, `input_media_too_large`, `budget_exceeded`, `spending_blocked`, `storage_quota_exceeded`
  - `errors` (object[], Optional, can be null)
    - `path` (string, Required)
    - `rule` (string, Required)
  - `message` (string, Required) Readable explanation. Do not parse it.
  - `request_id` (string, Required) Include this when you contact support.
  - `retryable` (boolean, Required) True for 429 and 503 only. Even then, check recent tasks before you send a create request again.
  - `task_id` (string, Optional) The task this error belongs to, when one exists.

| Status | What it means and what to do |
| --- | --- |
| 401 | The key is missing, malformed, expired or revoked. Correct the key on your server, then continue. |
| 402 | Available Credits cannot cover this request. Add Credits, wait for them to be credited, then check the balance. |
| 403 | The key scope, email verification, a budget or an account restriction blocks this. Check the key type, scopes and project budget. |
| 404 | The model or resource does not exist or is outside this project. Check the project, the ID and that the model is enabled. |
| 409 | The request conflicts with the current state. Read the resource again and decide whether to send the request again. |
| 422 | A field or value is invalid. Compare the request with the field table and the model page. |
| 429 | Too many requests. No task was created. Wait for the Retry-After time before sending again. |
| 500 | The server failed and the task may already be accepted. Do not resend; list recent tasks first. |
| 503 | The service is temporarily unavailable. For a create request, list recent tasks and confirm none was accepted before you submit again. |
| Timeout or disconnect | No response, or the connection dropped. The task may be accepted. With a task ID, read that task; without one, find it by client_reference in the task list. |

### cURL

```bash
curl -X POST "https://api.vizoapi.com/v1/generations" \
  -H "Authorization: Bearer $VIZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2-5",
    "input": {
      "content": [
        {
          "type": "text",
          "text": "A paper boat drifting on a pond"
        }
      ],
      "resolution": "720p",
      "duration": 5
    }
  }'
```

### Python

```python
import os, requests

res = requests.post(
    "https://api.vizoapi.com/v1/generations",
    headers={"Authorization": f"Bearer {os.environ['VIZO_API_KEY']}"},
    json={
      "model": "seedance-2-5",
      "input": {
        "content": [
          {
            "type": "text",
            "text": "A paper boat drifting on a pond"
          }
        ],
        "resolution": "720p",
        "duration": 5
      }
    },
    timeout=60,
)
print(res.status_code, res.json())
```

### Node.js

```javascript
const res = await fetch("https://api.vizoapi.com/v1/generations", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VIZO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "seedance-2-5",
    "input": {
      "content": [
        {
          "type": "text",
          "text": "A paper boat drifting on a pond"
        }
      ],
      "resolution": "720p",
      "duration": 5
    }
  }),
});
console.log(res.status, await res.json());
```
