# Receive a generation event

`generationEvent`

Event sent to your endpoint: `generationEvent`

Signed per the Standard Webhooks specification. Verify with an official Standard Webhooks library and the endpoint's whsec_ signing secret: it checks Base64(HMAC-SHA256(Base64-decoded secret, webhook-id + '.' + webhook-timestamp + '.' + raw_body)) against each v1 entry in webhook-signature in constant time and rejects timestamps more than five minutes from now. Deduplicate by webhook-id. Redelivery preserves the body and webhook-id and signs again with a new timestamp.

VizoAPI sends this request to the webhook endpoint you create in the console.

## Request headers

- `webhook-id` (string, Required) Unique event ID, equal to event_id in the body. Unchanged on retries and redelivery; use it to deduplicate.
- `webhook-timestamp` (string, Required) Unix time in seconds when this attempt was sent.
- `webhook-signature` (string, Required) Space-delimited list of v1 signatures. Two are sent for 24 hours after a secret rotation; accept the request if any one matches.

## Request body

- `billing_status` (string, Required) Pending awaits funding; unfunded closed without a hold; held means Credits are held for the task; settled charges verified delivery; released returns the hold; refunded reverses previously consumed generation Credits. Allowed values: `pending`, `unfunded`, `held`, `settled`, `released`, `refunded`
- `closed_status` (string, Required) Immutable customer closure. Unresolved means the resolution deadline passed without confirmed delivery. Allowed values: `succeeded`, `failed`, `canceled`, `unresolved`
- `created_at` (date-time, Required)
- `delivery_status` (string, Required) Managed output delivery state, independent of supplier execution. Allowed values: `pending`, `copying`, `ready`, `failed`
- `error_code` (string, Optional) Stable accepted-task failure code, matching generation error.code. Omitted when no failure code applies. Funding or recovery refusals, provider capacity, content policy, media validity, draft expiry and other execution failures remain distinct. 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`, `generation_failed`
- `event_id` (string, Required)
- `execution_status` (string, Required) Supplier execution state: processing until execution ends. Succeeded can precede verified media delivery. Allowed values: `processing`, `succeeded`, `failed`, `canceled`, `unresolved`
- `free` (boolean, Required)
- `late_result_available` (boolean, Required) A result that arrived after closing is provided at no charge.
- `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, Optional) Credits a refund returned to the balance: what this task had been charged. 0.000 unless billing_status is refunded. Absent from events created before this field was added.
  - `reserved` (string, Required) Credits held for this task when the event was created, 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`
- `result` (object, Required, can be null) Delivered assets, once available.
  - `asset_id` (string, Required)
- `task_id` (string, Required)
- `type` (string, Required) Allowed values: `generation.succeeded`, `generation.failed`, `generation.canceled`, `generation.unresolved`, `generation.refunded`, `generation.late_result_available`
- `version` (integer, Required)

```json
{
  "billing_status": "held",
  "closed_status": "succeeded",
  "created_at": "2026-11-02T08:01:43Z",
  "delivery_status": "pending",
  "error_code": "insufficient_balance",
  "event_id": "string",
  "execution_status": "processing",
  "free": false,
  "late_result_available": false,
  "price": {
    "charged": "0.000",
    "estimated": "157.000",
    "refunded": "0.000",
    "reserved": "157.000",
    "unit": "credit"
  },
  "result": null,
  "task_id": "gen_01JD8Z5QW3XR",
  "type": "generation.succeeded",
  "version": 1
}
```

## Responses

### 2XX Delivery accepted

```json
null
```

### cURL

```bash
# Your endpoint receives a POST signed per Standard Webhooks. Replay one locally to test your handler:
curl -X POST "$YOUR_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -H "webhook-id: $EVENT_ID" \
  -H "webhook-timestamp: $TIMESTAMP" \
  -H "webhook-signature: v1,$SIGNATURE" \
  --data-binary @event.json
```

### Python

```python
# pip install standardwebhooks
from standardwebhooks import Webhook, WebhookVerificationError

wh = Webhook("whsec_...")  # your endpoint's signing secret

def verify(headers, raw_body: bytes):
    try:
        return wh.verify(raw_body, headers)  # returns the parsed event
    except WebhookVerificationError:
        return None
```

### Node.js

```javascript
// npm install standardwebhooks
import { Webhook } from "standardwebhooks";

const wh = new Webhook(process.env.WEBHOOK_SECRET); // whsec_...

// rawBody is a Buffer of the request body as received, e.g. express.raw({ type: "application/json" }).
export function verify(headers, rawBody) {
  try {
    return wh.verify(rawBody, headers); // returns the parsed event
  } catch {
    return null;
  }
}
```
