---
type: AI Model
id: video-transition-api
title: Video Transition API
provider: Pixazo
description: "Join 2 to 4 clips with a real transition instead of a hard cut. Choose a `family` — fades, wipes, slides, smooth, geometric, diagonals, slices, wind, cover-reveal or texture — then name the exact effect in `transition`, giving you all 58 of ffmpeg's transitions rather than a handful. Set the length with `crossfade_seconds` and shape the audio crossfade with `audio_curve` (24 curves, including `nofade` to leave a music bed untouched). Video and audio are crossfaded together. MP4/MOV inputs, 60 seconds of combined source. For a plain join with no transition, use the Video Merge API, which stream-copies and is far cheaper."
resource: https://www.pixazo.ai/models/video-transition-api
docs_url: https://www.pixazo.ai/models/video-transition-api
latest_version: v1
tags:
  - video-transition
  - pixazo
variants:
  - id: media-transition-v1
    name: Video Transition 1.0
    version: 1.0
    capabilities:
      - Transition
timestamp: 2026-08-25T08:44:38.582Z
---

# Video Transition API

> Provider: **Pixazo**
> Source: https://www.pixazo.ai/models/video-transition-api

Join 2 to 4 clips with a real transition instead of a hard cut. Choose a `family` — fades, wipes, slides, smooth, geometric, diagonals, slices, wind, cover-reveal or texture — then name the exact effect in `transition`, giving you all 58 of ffmpeg's transitions rather than a handful. Set the length with `crossfade_seconds` and shape the audio crossfade with `audio_curve` (24 curves, including `nofade` to leave a music bed untouched). Video and audio are crossfaded together. MP4/MOV inputs, 60 seconds of combined source. For a plain join with no transition, use the Video Merge API, which stream-copies and is far cheaper.

## Video Transition 1.0

### Transition

## Base URL

```
https://gateway.pixazo.ai/media-tools/v1/video-transition
```

## Authentication

All requests require an API key passed via header.

**Pricing:** Billed at **$0.004 per second of the produced video** — the total length of the clips you join. Joining three 30-second clips costs $0.18. Combined source is capped at 60 seconds.

**Rounding:** billing is per second but always rounds **up to a whole second** — a 5.06-second source bills as 6 seconds. The shortest billable job is 1 second.

**Retries:** this is an asynchronous job on shared encoding capacity, so a request can occasionally come back `processing_failed` or take much longer than usual. These are transient and succeed on a retry, and a failed job is **never charged** — the wallet hold is released. If you chain these tools, retry a failed step rather than failing the whole pipeline.

**Inputs must be MP4 or MOV.** Anything else — WebM, MKV, AVI — is rejected up front with `every video_urls entry must be a readable MP4/MOV`. The reason is billing, not capability: a merge is priced on the SUM of its clips, so every clip’s duration has to be measured before the job is accepted, and that measurement reads the MP4/MOV container only. Rejecting is deliberate — guessing a duration would mis-charge you. Convert other formats with the **Video Converter API** first, then merge.

Header

Type

Required

Description

Ocp-Apim-Subscription-Key

string

Yes

Your API subscription key

## Video Transition generate request

## Request Code

HTTP Python JavaScript cURL

```
POST https://gateway.pixazo.ai/media-tools/v1/video-transition
Content-Type: application/json
Cache-Control: no-cache
Ocp-Apim-Subscription-Key: YOUR_API_KEY

{
  "video_urls": [
    "https://api-assets.pixazo.ai/media-api-test/t.mov",
    "https://api-assets.pixazo.ai/media-api-test/t.mov"
  ],
  "family": "fades",
  "transition": "dissolve",
  "crossfade_seconds": 1.0
}
```

```
import requests

url = "https://gateway.pixazo.ai/media-tools/v1/video-transition"
headers = {
    "Content-Type": "application/json",
    "Cache-Control": "no-cache",
    "Ocp-Apim-Subscription-Key": "YOUR_API_KEY"
}
data = {
    "video_urls": [
        "https://api-assets.pixazo.ai/media-api-test/t.mov",
        "https://api-assets.pixazo.ai/media-api-test/t.mov"
    ],
    "family": "fades",
    "transition": "dissolve",
    "crossfade_seconds": 1.0
}

response = requests.post(url, json=data, headers=headers)
print(response.json())
```

```
const url = "https://gateway.pixazo.ai/media-tools/v1/video-transition";
const headers = {
  "Content-Type": "application/json",
  "Cache-Control": "no-cache",
  "Ocp-Apim-Subscription-Key": "YOUR_API_KEY"
};
const data = {
  "video_urls": [
    "https://api-assets.pixazo.ai/media-api-test/t.mov",
    "https://api-assets.pixazo.ai/media-api-test/t.mov"
  ],
  "family": "fades",
  "transition": "dissolve",
  "crossfade_seconds": 1.0
};

fetch(url, {
  method: "POST",
  headers: headers,
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));
```

```
curl -X POST "https://gateway.pixazo.ai/media-tools/v1/video-transition" \
  -H "Content-Type: application/json" \
  -H "Cache-Control: no-cache" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  --data-raw '{
    "video_urls": [
      "https://api-assets.pixazo.ai/media-api-test/t.mov",
      "https://api-assets.pixazo.ai/media-api-test/t.mov"
    ],
    "family": "fades",
    "transition": "dissolve",
    "crossfade_seconds": 1.0
  }'
```

## Output

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

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

## Webhook (Optional)

Add the `X-Webhook-URL` header to your generate request to receive a POST callback instead of polling.

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

## Request Parameters - Video Transition generate request

Parameter

Required

Type

Default

Allowed values / range

Description

video\_urls

Yes

array of strings

—

2 – 4 items; each an HTTP(S) URL to an **MP4 or MOV**; combined length ≤ 60 s

The clips to join, in the order given, with a transition between each pair. Every entry must be readable — if any one cannot be measured the request is rejected before you are charged.

family

Yes

enum

—

`fades`, `wipes`, `slides`, `smooth`, `geometric`, `diagonals`, `slices`, `wind`, `cover-reveal`, `texture`

Which _group_ of transitions to use. Pick the family for the effect you want — a dip or blend (`fades`), a travelling edge (`wipes`, `smooth`, `diagonals`), a moving clip (`slides`, `cover-reveal`), a shape opening or closing (`geometric`), banded or streaky dissolves (`slices`, `wind`), or an optical effect (`texture`). Then name the exact one in `transition`.

transition

Yes

enum

—

Depends on `family` — see **Transitions by family** below

The specific transition, which **must belong to the family you named**. A valid transition from the wrong family is rejected with a 400 listing that family's values, so the two fields can never disagree silently.

audio\_curve

No

enum

`tri`

`nofade`, `tri`, `qsin`, `esin`, `hsin`, `log`, `ipar`, `qua`, `cub`, `squ`, `cbr`, `par`, `exp`, `iqsin`, `ihsin`, `dese`, `desi`, `losi`, `sinc`, `isinc`, `quat`, `quatr`, `qsin2`, `hsin2`

The fade shape applied to the **audio** at each join. `tri` (the default) is a straight linear crossfade. `nofade` leaves the audio untouched through the join — useful when a continuous music bed should not dip. The rest are easing curves: `qsin`, `hsin` and `esin` are sine-based and sound gentler than linear; `log`, `exp` and `par` weight the fade toward one side.

crossfade\_seconds

No

number

`1.0`

0.2 – 3

How long each transition lasts. It must be **shorter than the first and last clips, and at most half of any clip between them** — otherwise the request is rejected with a message naming the clip. That rule is deliberate: a longer fade would consume a clip entirely and silently drop it from the output.

target\_resolution

No

enum

— (matches the first clip)

`480p`, `720p`, `1080p`

Normalise every clip to this size before joining. Omit it and the first clip's dimensions are used.

**Transitions by family.** Both `family` and `transition` are required, and the transition must be one of the values listed for the family you chose. The **bold** value in each row is a good default if you have no preference. All 58 are available.

family

Valid `transition` values

What it looks like

`fades`

**`fade`**, `fadeblack`, `fadewhite`, `fadegrays`, `fadefast`, `fadeslow`, `dissolve`

Blends and dips. Straight cross-dissolves, dips through black/white/grey, and a grainy per-pixel dissolve.

`wipes`

**`wipeleft`**, `wiperight`, `wipeup`, `wipedown`, `wipetl`, `wipetr`, `wipebl`, `wipebr`

A hard edge travels across the frame, revealing the next clip. Four sides plus four corners.

`slides`

**`slideleft`**, `slideright`, `slideup`, `slidedown`

Both clips move together — the outgoing one is pushed off frame.

`smooth`

**`smoothleft`**, `smoothright`, `smoothup`, `smoothdown`

The same directions as a wipe, but with a soft, ramped edge instead of a hard line.

`geometric`

**`circleopen`**, `circleclose`, `circlecrop`, `rectcrop`, `vertopen`, `vertclose`, `horzopen`, `horzclose`, `radial`

A shape opens or closes over the frame. `radial` sweeps around the centre like a clock hand.

`diagonals`

**`diagtl`**, `diagtr`, `diagbl`, `diagbr`

The boundary runs corner to corner.

`slices`

**`hlslice`**, `hrslice`, `vuslice`, `vdslice`

The frame is cut into bands that swap one after another.

`wind`

**`hlwind`**, `hrwind`, `vuwind`, `vdwind`

A streaky, directional dissolve, as if blown across the frame.

`cover-reveal`

**`coverleft`**, `coverright`, `coverup`, `coverdown`, `revealleft`, `revealright`, `revealup`, `revealdown`

One clip moves over or off a stationary one. `cover*` slides the incoming clip on top; `reveal*` slides the outgoing clip away to expose it.

`texture`

**`zoomin`**, `pixelize`, `hblur`, `distance`, `squeezeh`, `squeezev`

Optical and sampling effects rather than a moving boundary — zoom, blur, pixelate, squeeze.

## Example Request

```
{
  "video_urls": [
    "https://api-assets.pixazo.ai/media-api-test/t.mov",
    "https://api-assets.pixazo.ai/media-api-test/t.mov"
  ],
  "family": "fades",
  "transition": "dissolve",
  "crossfade_seconds": 1.0
}
```

## Response

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

## Request Headers

Header

Value

Content-Type

application/json

Cache-Control

no-cache

Ocp-Apim-Subscription-Key

YOUR\_API\_KEY

## Response Handling

Common status codes.

Code

Meaning

202

Accepted — Request queued

400

Bad Request

401

Unauthorized

402

Insufficient Balance

403

Forbidden

429

Too Many Requests

500

Internal Server Error

## Error Responses

Queue system errors and model validation errors.

### Queue System Errors

```
// 402 — Insufficient balance
{
  "error": "Insufficient Balance",
  "message": "Your wallet does not have enough balance."
}
```

```
// 400 — Model not found
{
  "error": "Model not found",
  "message": "Model 'media-transition' not found or is disabled"
}
```

### Error via Status/Webhook

```
{
  "request_id": "media-transition_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "ERROR",
  "model_id": "media-transition",
  "error": "Description of the error",
  "output": null
}
```

## Retrieving Results

Poll the universal status endpoint to check progress and retrieve results.

### Endpoint

```
GET https://gateway.pixazo.ai/v2/requests/status/{request_id}
Ocp-Apim-Subscription-Key: YOUR_API_KEY
```

## cURL Example

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

## Response (Completed)

```
{
  "request_id": "media-transition_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "COMPLETED",
  "model_id": "media-transition",
  "error": null,
  "output": {
    "media_url": [
      "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/media-transition_019dxxxx/output.mp4"
    ],
    "media_type": "video/mp4"
  },
  "created_at": "2026-03-31T10:00:00.000Z",
  "updated_at": "2026-03-31T10:00:15.000Z",
  "completed_at": "2026-03-31T10:00:15.000Z"
}
```

## Response Fields

Field

Type

Description

request\_id

string

Unique request identifier

status

string

QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR

model\_id

string

Model that processed the request

error

string|null

Error message if failed

output.media\_url

array

URLs to generated media (R2 CDN)

output.media\_type

string

MIME type of the output

created\_at

string

When request was created

completed\_at

string

When request completed

polling\_url

string

Status URL (initial response only)

## Status Values

Status

Description

QUEUED

Request accepted, waiting to be processed

PROCESSING

Being processed by the model

COMPLETED

Done — output contains the result

FAILED

Failed — check error field

ERROR

System error — not charged

## Status Flow

```
QUEUED → PROCESSING → COMPLETED
                    → FAILED
                    → ERROR
```

## Typical Workflow

1.  **Send a generate request** to the API endpoint
2.  **Save the `request_id`** from the response
3.  **Poll** every 5-10 seconds: `GET /v2/requests/status/{request_id}`
4.  **When `status` is `"COMPLETED"`**, download from `output.media_url`

**Tip:** Use `X-Webhook-URL` header to get a callback instead of polling.
