---
type: AI Model
id: video-to-previs
title: Video to Previs
provider: Pixazo
description: "Shot2Previs converts a video shot into a temporally consistent previs (previsualization) reference — a clay-shaded 3D depth render with multi-person pose skeletons that captures the shot's camera movement, framing, and subject blocking without reproducing any pixels. Pass a video URL, poll the request, download the previs mp4; feed it to a generative video model (Seedance, Wan-VACE, LTX) as a structural reference. Optional green-screen mode isolates the performer."
resource: https://www.pixazo.ai/models/video-to-previs
docs_url: https://www.pixazo.ai/models/video-to-previs
latest_version: v1
tags:
  - video-to-video
  - pixazo
variants:
  - id: shot2previs-v1
    name: Video to Previs
    version: 1.0
    capabilities:
      - Video to Video (Previs — Depth + Pose Reference)
timestamp: 2026-07-17T16:20:02.152Z
---

# Video to Previs

> Provider: **Pixazo**
> Source: https://www.pixazo.ai/models/video-to-previs

Shot2Previs converts a video shot into a temporally consistent previs (previsualization) reference — a clay-shaded 3D depth render with multi-person pose skeletons that captures the shot's camera movement, framing, and subject blocking without reproducing any pixels. Pass a video URL, poll the request, download the previs mp4; feed it to a generative video model (Seedance, Wan-VACE, LTX) as a structural reference. Optional green-screen mode isolates the performer.

## Video to Previs

### Video to Video (Previs — Depth + Pose Reference)

## Overview

Shot2Previs converts any input video shot into a temporally consistent **previs** (previsualization) reference video — a clay-shaded 3D depth render with multi-person pose skeletons that captures the shot's camera movement, framing, and subject blocking without reproducing any of its pixels. Feed the output to a generative video model (e.g. Seedance `@video`, Wan-VACE, LTX IC-LoRA) to regenerate the scene with new characters, environments, and style while preserving the original cinematography.

Asynchronous queue API: submit a video URL, poll the request status (or use a webhook), then download the result from the returned media URL. Processing runs on GPU; a 10–15 second clip completes in roughly 45–70 seconds.

## Video to Previs API Documentation

```
POST https://gateway.pixazo.ai/shot2previs/v1/video-to-video
```

## Authentication

All requests require an API key passed via header.

Header

Type

Required

Description

Ocp-Apim-Subscription-Key

string

Yes

Your API subscription key

## Create a Previs Job — Video to Previs

## How to pass the video

The input video is passed as a **URL in the JSON body** (field `video_url`) — not as a file upload. Host the clip anywhere publicly fetchable (a signed URL is fine); the service downloads it server-side. MP4/MOV, up to **200 MB**.

```
{
  "video_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4"
}
```

Do not send `multipart/form-data` — the request body is plain `application/json`.

## Request Code

HTTP Python JavaScript cURL

```
POST https://gateway.pixazo.ai/shot2previs/v1/video-to-video HTTP/1.1
Ocp-Apim-Subscription-Key: YOUR_API_KEY
Content-Type: application/json

{
  "video_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4"
}
```

```
import requests, time

API_KEY = "YOUR_API_KEY"
headers = {"Ocp-Apim-Subscription-Key": API_KEY, "Content-Type": "application/json"}

# 1. Submit — the video is passed as a URL, not a file upload
submit = requests.post(
    "https://gateway.pixazo.ai/shot2previs/v1/video-to-video",
    headers=headers,
    json={"video_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4"},
)
job = submit.json()
print(job)  # {"request_id": "...", "status": "QUEUED", "polling_url": "..."}

# 2. Poll until terminal
while True:
    status = requests.get(job["polling_url"], headers=headers).json()
    print(status["status"])
    if status["status"] in ("COMPLETED", "FAILED", "ERROR"):
        break
    time.sleep(10)

# 3. Download the previs video
if status["status"] == "COMPLETED":
    url = status["output"]["media_url"][0]
    open("previs.mp4", "wb").write(requests.get(url).content)
```

```
const API_KEY = "YOUR_API_KEY";
const headers = {
  "Ocp-Apim-Subscription-Key": API_KEY,
  "Content-Type": "application/json",
};

// 1. Submit — the video is passed as a URL, not a file upload
const submit = await fetch("https://gateway.pixazo.ai/shot2previs/v1/video-to-video", {
  method: "POST",
  headers,
  body: JSON.stringify({ video_url: "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4" }),
});
const job = await submit.json(); // { request_id, status: "QUEUED", polling_url }

// 2. Poll until terminal
let status;
do {
  await new Promise(r => setTimeout(r, 10000));
  status = await (await fetch(job.polling_url, { headers })).json();
  console.log(status.status);
} while (!["COMPLETED", "FAILED", "ERROR"].includes(status.status));

// 3. status.output.media_url[0] is the previs mp4 URL
console.log(status.output?.media_url?.[0]);
```

```
curl -X POST "https://gateway.pixazo.ai/shot2previs/v1/video-to-video" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"video_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4"}'
```

## Output

```
{
  "request_id": "shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "QUEUED",
  "polling_url": "https://gateway.pixazo.ai/v2/requests/status/shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

[Try Now](https://api.pixazo.ai/api-details#api=shot2previs&operation=shot2previs-video-to-video)

## Webhook (Optional)

Add the `X-Webhook-URL` header to your submit request to receive a `POST` callback when the job completes — no polling required.

**Using curl?** These are HTTP request headers — pass each with `-H`, e.g. `-H "X-Webhook-URL: https://your-server.com/webhook/callback"`. Do not paste them as bare lines, and end every line of a multi-line command with `\`.

### Webhook Headers

Header

Required

Default

Description

`X-Webhook-URL`

Yes (to enable)

—

HTTPS endpoint on your server that will receive the `POST` callback. Must respond `2xx` within a few seconds (process async if needed).

`X-Webhook-Mode`

No

`terminal`

`terminal` — fires once at the final status (`COMPLETED`/`FAILED`/`ERROR`). `sync` — fires on every poll cycle plus the terminal event, and caps the queue’s polling delay at **15s** for tighter progress updates.

### Example: enable webhook

```
X-Webhook-URL: https://your-server.com/webhook/callback
X-Webhook-Mode: terminal
```

### Callback Payload

Your endpoint receives a `POST application/json` with the same shape as the `GET /v2/requests/status/{request_id}` response. Example terminal callback (mode `terminal`):

```
{
  "request_id": "shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "COMPLETED",
  "model_id": "shot2previs",
  "error": null,
  "output": {
    "media_url": [
      "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/output.mp4"
    ],
    "media_type": "video/mp4"
  },
  "created_at": "2026-07-07T10:15:32.110Z",
  "updated_at": "2026-07-07 10:16:41",
  "completed_at": "2026-07-07 10:16:41"
}
```

### Failure callback shape

```
{
  "request_id": "shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "ERROR",
  "model_id": "shot2previs",
  "error": "Description of the error",
  "output": null,
  "created_at": "...",
  "updated_at": "...",
  "completed_at": "..."
}
```

### Delivery semantics

-   **terminal mode (default)** — exactly one `POST` when the request reaches a terminal status. No callback during `PROCESSING`.
-   **sync mode** — `POST` on every status poll (with delay capped at ~15s) plus a final `POST` at terminal status. Use when you want progress updates.
-   **Idempotency** — use `request_id` as your idempotency key. Network retries can deliver the same callback more than once; your handler must tolerate duplicates.
-   **Response** — respond `200 OK` within a few seconds. The queue does not block on slow handlers, but persistent failures may stop further deliveries.
-   **HTTPS required** — plain `http://` URLs are rejected.

## Request Parameters — Video to Previs

Parameter

Required

Type

Default

Allowed values / range

Description

`video_url`

Yes

string (URL)

—

Public MP4/MOV URL, ≤ 200 MB

The input shot, passed as a **publicly fetchable URL** (not a file upload). The service downloads it server-side. Any resolution/frame-rate; it is normalized by `fps` / `max_height`.

`style`

No

string

`clay`

`clay`, `depth`, `pose`, `edge` (comma-separated)

Output track(s). `clay` = matcap-shaded 3D look. `depth` = grayscale depth. `pose` = skeletons on black. `edge` = line render. The completed response returns the primary previs video (first available of clay/depth/pose/edge).

`pose`

No

boolean

`true`

`true`, `false`

Overlay multi-person pose skeletons on the `clay`/`depth` output.

`greenscreen`

No

boolean

`false`

`true`, `false`

Isolate the performer via person segmentation and remove everything else (green screen, floor, markers, studio equipment).

`sbs`

No

boolean

`false`

`true`, `false`

Also render a side-by-side comparison video (the source shot beside the previs) as an additional output, useful for checking that camera move, framing and blocking were tracked faithfully. Left off by default so the job returns a single deliverable — the previs video.

`model`

No

string

`small`

`small`, `base`

Depth model size. `small` is fast and sufficient for most shots; `base` is higher fidelity at greater cost.

`fps`

No

float

`24`

1–60

Output frame-rate cap. Source is resampled to constant frame rate at or below this value.

`max_height`

No

integer

`720`

256–1080

Frames are downscaled so height ≤ this before processing (aspect preserved).

`ema`

No

float

`0.6`

0.0–0.95

Temporal smoothing strength. Higher = smoother motion; hard cuts are auto-detected and reset.

`start`

No

string

—

`HH:MM:SS` or seconds

Trim the input to start at this timestamp before processing. Trimming reduces billed input seconds.

`end`

No

string

—

`HH:MM:SS` or seconds

Trim the input to end at this timestamp before processing.

## Example Request

```
POST https://gateway.pixazo.ai/shot2previs/v1/video-to-video
Ocp-Apim-Subscription-Key: YOUR_API_KEY
Content-Type: application/json

{
  "video_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/boxing_day.mp4",
  "style": "clay",
  "model": "small",
  "fps": 24,
  "max_height": 720,
  "ema": 0.6,
  "pose": true,
  "greenscreen": false,
  "start": "00:00:02",
  "end": "00:00:12"
}
```

## Response

HTTP `202 Accepted` — the request is queued. Save `request_id` and poll `polling_url`.

```
{
  "request_id": "shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "QUEUED",
  "polling_url": "https://gateway.pixazo.ai/v2/requests/status/shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

## Request Headers

Header

Required

Value

`Ocp-Apim-Subscription-Key`

Yes

Your API subscription key

`Content-Type`

Yes

`application/json`

`X-Webhook-URL`

No

HTTPS callback URL (see Webhook section)

`X-Webhook-Mode`

No

`terminal` (default) or `sync`

## Response Handling

Status Code

Meaning

Action

`202`

Request accepted and queued

Poll `polling_url` (or wait for your webhook)

`400`

Invalid parameters (bad `video_url`, unknown `style`, …)

Fix the request body and retry

`401`

Missing or invalid subscription key

Check the `Ocp-Apim-Subscription-Key` header

`402`

Insufficient wallet balance

Top up your account balance

`403`

Key not authorized for this API

Verify your subscription/product access

`429`

Rate limit exceeded

Back off and retry after a delay

`500`

Internal error

Retry; contact support if persistent

## Error Responses

Submit-time failures return a JSON error immediately (e.g. `402`):

```
{
  "error": "Insufficient balance",
  "message": "Your wallet balance is too low to run this request."
}
```

Failures after queuing (bad source URL, pipeline error) surface through the status endpoint / webhook with `status: "ERROR"` and a populated `error` field — see the failure callback shape above. Failed requests are not billed.

## Retrieving Results

Poll the status endpoint with the `request_id` from the submit response:

```
GET https://gateway.pixazo.ai/v2/requests/status/{request_id}
```

### cURL Example

```
curl "https://gateway.pixazo.ai/v2/requests/status/shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \\
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"
```

### Response (Completed)

```
{
  "request_id": "shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "COMPLETED",
  "model_id": "shot2previs",
  "error": null,
  "output": {
    "media_url": [
      "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/shot2previs_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/output.mp4"
    ],
    "media_type": "video/mp4"
  },
  "created_at": "2026-07-07T10:15:32.110Z",
  "updated_at": "2026-07-07 10:16:41",
  "completed_at": "2026-07-07 10:16:41"
}
```

`output.media_url[0]` is a direct, downloadable URL of the previs video (hosted on our CDN) — a plain `GET` with no auth headers.

## Response Fields

Field

Type

Description

`request_id`

string

Unique id of your request; use it to poll and as your idempotency key

`status`

string

`QUEUED` | `PROCESSING` | `COMPLETED` | `FAILED` | `ERROR`

`model_id`

string

Always `shot2previs`

`error`

string | null

Error description when `status` is `ERROR`/`FAILED`

`output.media_url`

string\[\]

Download URL(s) of the previs video (mp4)

`output.media_type`

string

`video/mp4`

`created_at` / `completed_at`

string

Request lifecycle timestamps

`polling_url`

string

Convenience URL for status polling (submit response only)

## Status Values

Status

Meaning

`QUEUED`

Accepted; waiting for a worker

`PROCESSING`

Previs generation in progress on GPU

`COMPLETED`

Done — `output.media_url` is ready

`FAILED` / `ERROR`

Terminal failure — see `error`; not billed

## Status Flow

```
QUEUED -> PROCESSING -> COMPLETED
                     \-> FAILED / ERROR
```

## Typical Workflow

1.  POST the JSON body with your `video_url` → get `request_id`
2.  Poll `GET /v2/requests/status/{request_id}` every 10–15s (or use a webhook)
3.  On `COMPLETED`, download `output.media_url[0]`
4.  Use the previs mp4 as a structural reference in your generative video pipeline

## Notes

-   **Billing** — $0.05 per second of _input_ video (after `start`/`end` trimming). A 10-second clip costs $0.50. Failed requests are not billed.
-   **Input** — `video_url` must be publicly fetchable (signed URLs are fine); MP4/MOV up to 200 MB.
-   **Output** — one previs mp4 per request (the first available of `clay`/`depth`/`pose`/`edge` per your `style`). The side-by-side (`sbs`) preview is not returned through this API.
-   **No pixels are copied** — the previs is a synthetic 3D render of scene structure; it contains no source footage.
