---
title: "Poll a video run bought with an x402 payment"
method: GET
path: "/api/x402/video"
---

# Poll a video run bought with an x402 payment

`GET /api/x402/video`

## Request

- Base URL: `https://www.trezalabs.com`
- URL: `https://www.trezalabs.com/api/x402/video`
- Auth: HTTP bearer

Returns the run's status and, once it has finished, the video URL. The paid POST returns the result when the render finishes within its wait, so this is for a run whose POST ended with status running, was sent async, or lost its connection: the POST's X-Status-Url header carries this URL from the first byte. The token is the claim ticket handed back by the paid POST, and is the only credential needed. Send the header Prefer: wait=N to hold the answer until the run finishes, for up to N seconds (at most 720), streamed the same way as the paid POST (a whitespace byte every 2 seconds, then the JSON); Preference-Applied echoes it. The video URL carries a download marker (c=) among its query parameters; use it exactly as given. A run that failed answers with the provider's error, a reason (prompt_refused or render_failed), and a retryUrl; nothing is charged for a failed render, so the payment stays on the wallet balance and the retry spends it. Once it has been retried, it answers with retriedBy (the retry's runId and statusUrl) instead, and retryable false. A render that outlasted its deadline reads running with a note while the clip is collected, then success with the video. Called with no query parameters at all, this returns the offer list instead: every model on sale with what it is for, whether it takes a first frame, and its prices, plus the request fields, the limits, and how to buy one.

## Query parameters

- `runId` string
- `token` string

## Headers

- `Prefer` string

## Response `200`

Run status plus the video URL once it has finished; or, when called with no query parameters, the offer list (service, description, howToBuy, fields, models[], offers[], limits, delivery)

- union
  - object
    - `runId` string, required
    - `status` 'running' | 'success' | 'partial' | 'error' | 'cancelled', required: running until the render finishes; success carries the video; partial, error, and cancelled carry the failure fields.
    - `startedAt` string, date-time
    - `finishedAt` string, date-time
    - `durationMs` integer
    - `pollAfterMs` integer: While running: how long to wait before polling again.
    - `video` string, uri: URL of the finished video. Use it exactly as given: its query parameters, including c=, are part of it.
    - `outputs` object
    - `error` string: Failed runs only. What went wrong, in the provider's words.
    - `failedStep` string: Failed runs only. The step that failed, e.g. Video Generation.
    - `reason` 'prompt_refused' | 'render_failed': Failed runs only. prompt_refused: the model declined the prompt or image, so reword it. render_failed: the render did not finish; the same prompt may succeed.
    - `retryable` boolean: Failed runs only. True until the run's one free retry has been used, then false.
    - `retryUrl` string, uri: Failed runs only, until retried. POST here to render again on the wallet balance, optionally with {"prompt": "..."} in the body. Carries the same signed ticket.
    - `retriedBy` object: Failed runs only, once retried: the retry. Poll its statusUrl for the result.
      - `runId` string
      - `statusUrl` string, uri
    - `retriedByRunId` string: Failed runs only, once retried: the run the retry started (also retriedBy.runId).
    - `note` string: Set while a render that outlasted its deadline is being collected from the provider: status stays running until the clip arrives, then turns success with the video.
    - `message` string: Failed runs only. What happened and what to do, in one sentence.
    - `balanceUsd` number: Failed runs only. Credit left on the paying wallet, which the retry spends.
    - `retryOf` string: Set on a run started by a retry: the failed run it replaces.
  - object: Returned when the GET carries no query parameters: what is on sale, the prices, and how to buy.
    - `service` string, required
    - `description` string
    - `howToBuy` object, required: The request to send: method, an example body, and how payment works.
      - `method` string
      - `body` object
      - `note` string
    - `fields` object, required: Each request field and what it takes.
    - `models` object[]
      - `id` string
      - `label` string
      - `default` boolean
      - `firstFrame` boolean: Whether it takes an image_url.
      - `note` string: What it is for.
      - `prices` object[]
        - `seconds` number
        - `priceUsd` number
    - `offers` object[]: Every model, length and aspect ratio on sale, with its price.
      - `model` string
      - `seconds` number
      - `aspectRatio` string
      - `priceUsd` number
    - `limits` object: maxPromptChars, and the seconds, aspectRatio and model values on sale.
    - `delivery` string: How the paid call answers and where the file ends up.
    - `alreadyPaid` string: Where a file already paid for can be collected, for a buyer that lost its statusUrl.

## Other responses

- `400`: One of runId and token was given without the other. Supply both to poll a run, or neither to get the offer list. The runId contains '#', so a hand-built URL must keep it encoded as %23; use statusUrl exactly as returned.
- `403`: Invalid, expired, or mismatched token
- `404`: Run not found

---

[API](https://skmtc.dev/trezalabs/apis/treza-pipelines-api.md) · [All operations](https://skmtc.dev/trezalabs/apis/treza-pipelines-api/llms.txt) · [OpenAPI document](https://skmtc.dev/trezalabs/apis/treza-pipelines-api/revisions/a76574c1731b?raw)
