---
title: "Concatenate two videos you own"
method: POST
path: "/v1/videos/merge"
tags: ["Videos"]
---

# Concatenate two videos you own

`POST /v1/videos/merge`

## Request

- Base URL: `https://contentmaschine.ai/api`
- URL: `https://contentmaschine.ai/api/v1/videos/merge`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://contentmaschine.ai/api/oauth/authorize`, token URL `https://contentmaschine.ai/api/oauth/token`)

Joins exactly two videos already in your library, in the order given, into one new
video. Input is FILE REFERENCES, never a multi-file upload. There is no N-way merge.

**SYNCHRONOUS. There is no job to poll, and there is a hard latency ceiling.**
The merge runs inside this request via ffmpeg. Which path runs decides everything:
two clips that already share codec, resolution, frame rate and pixel format are
stream-copied (`merge_method: lossless`); anything else is fully re-encoded
(`reencode`), roughly an order of magnitude slower. Clips from two different
generation models routinely differ, so the slow path is not an edge case.

MEASURED on the deployed stack (2026-08-31):
```
lossless  2 x  30 s in ->  60 s out :   4.2 s   200
lossless  2 x 180 s in -> 360 s out :   7.0 s   200
reencode  2 x  30 s in ->  60 s out :  32.7 s   200
reencode  2 x 180 s in              : 120.2 s   504
```
The ceiling is the gateway read timeout of 120 seconds, not a limit this API can
raise from PHP. The re-encode path costs about 0.55 s per second of OUTPUT, so treat
**about 3 minutes of COMBINED input as the practical limit for mismatched clips**.
Past it you receive a bare gateway 504 with NO JSON body - the only response on this
API that is not the standard envelope - the work is discarded, and no output file is
registered. The stream-copy path is unconstrained at any length this API can ingest,
because the 48 MB per-file upload cap binds first.

`credits_used` is always 0 today. Merging is not currently billed; the field is
returned explicitly rather than left to be inferred.

## Request body

- object
  - `file_uuids` string[], required: Exactly two uuids of videos you own, in join order.

## Response `200`

The merged video.

- object
  - `success` boolean
  - `data` object
    - `file_uuid` string, uuid
    - `download_url` string: Authenticated download path for the merged file.
    - `merge_method` 'lossless' | 'reencode': Which ffmpeg path ran.
    - `credits_used` number, float: Always 0 today.
  - `timestamp` string, date-time

## Other responses

- `400`: Not exactly two file_uuids, or a malformed body.
- `401`: Missing or invalid API key.
- `404`: A file_uuid is unknown or not yours.
- `415`: One of the files is not a video.
- `504`: Gateway timeout at 120 s. NOT a JSON envelope - this response comes from the gateway, not from the application. The merge was discarded and no file was created. Retry with shorter inputs, or with clips that share codec/resolution/frame rate so the stream-copy path runs.
- `default`: Any other error. Every failure this API emits uses the same envelope; branch on `error.type`, never on `error.message`, and quote `error.correlation_id` to support.

---

[API](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api.md) · [All operations](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api/revisions/28c74f46051c?raw)
