---
title: "Media rights"
description: "Who is responsible for the footage roasOS edits, whose face needs a consent record, and the contract changes of 2026-08-21 and 2026-10-03."
url: https://docs.roasos.com/concepts/media-rights
---

# Media rights

roasOS holds two rules about the media in a paid request. Both rules are enforced at the door, before the price.

1. **You are responsible for the rights to the footage you edit.** roasOS edits a Discover creative like any other clip.
2. **A real person's face or voice needs a consent record.** The record is a versioned attestation in the request body.

This page states both rules. It also states each change to a published contract, because a change that is not published is a surprise.

## Rule 1 — you are responsible for the footage you edit

The roasOS Discover library holds real ads that other companies ran. Each one lives under `discover/items/v2/…` on `https://cdn.roasos.com`.

You can analyze a Discover creative to learn the structure, the hook and the pacing, and build your own ad from it. You can also edit it directly: recast it, swap your product into it, or dub it. Before you edit footage that another company made, make sure that you have the right to use it. The [terms](https://www.roasos.com/terms) make you responsible for that.

| Operation                                                                                                | A Discover creative is                               |
| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| [`POST /v1/workflows/analyze`](/workflows/analyze-an-ad)                                                 | Permitted                                            |
| [`POST /v1/workflows/remix`](/workflows/remix-an-ad), in `discover_item_id`                              | Permitted. The remix reads the ad and re-creates it. |
| Edit doors: recast, video edit, Seedance 2.5 edit, dub, captions, reframe, music, assembly, product shot | Permitted                                            |
| The brand kit logo                                                                                       | Refused with `400 discover_source_not_allowed`       |

## What changed on 2026-10-03

The edit doors accept a Discover creative again. Before this date they answered `400 discover_source_not_allowed`. The rule is now that you, not roasOS, decide whether you have the rights to the footage you edit. No request that roasOS accepted before is refused now.

## What changed on 2026-08-21 (reversed on 2026-10-03)

The `public-api-contracts@2026-08-21.v27` and `model-endpoint-contracts@2026-08-21.v8` versions carry two changes to this page's rules. The first refuses a request that roasOS used to accept. The second refuses nothing.

### The narrowing: the raw video-edit lanes refuse a Discover source

| Endpoint                                                                        | Before                     | Now                               |
| ------------------------------------------------------------------------------- | -------------------------- | --------------------------------- |
| `POST /v1/video-edit/kling-o3-pro` (removed 2026-10-29)                         | Accepted a Discover source | `400 discover_source_not_allowed` |
| `POST /v1/video-edit/kling-o3` (removed 2026-10-29)                             | Accepted a Discover source | `400 discover_source_not_allowed` |
| [`POST /v1/video-edit/gemini-omni-flash`](/models/video-edit/gemini-omni-flash) | Accepted a Discover source | `400 discover_source_not_allowed` |

**Why.** [`POST /v1/workflows/recast`](/workflows/recast-a-video) already refused a Discover creative, and it runs on these exact endpoints. The rule was therefore true one level up and false one level down: a caller who skipped the workflow could edit a competitor's ad through the raw lane. That was a bypass of a published promise, not a feature. The dub family already refused a Discover source for the same reason, so the three video-edit lanes now match the rest of the platform.

`POST /v1/workflows/analyze` is unchanged. It still reads a Discover creative, and it must: you learn from a competitor's ad by reading it. The narrowing covers the edit lanes only.

**What to do instead.** Analyze the ad, then edit your own footage. Refer to [Analyze an ad](/workflows/analyze-an-ad) and to [Remix an ad](/workflows/remix-an-ad).

<Callout>
  `gemini-omni-flash` video edit is not available to users in the EEA, in Switzerland and in the United Kingdom. This is the provider's own restriction, and it is separate from the rights rule above.
</Callout>

### The addition: VEED Lipsync v2 accepts a consent record

[`POST /v1/lipsync/veed-lipsync-v2`](/models/lipsync/veed-lipsync-v2) re-lips a real face in real footage. It now **accepts** an optional `media_rights` block. Nothing is refused that was accepted before.

```json
{
  "video_url": "https://cdn.roasos.com/workspaces/.../clip.mp4",
  "audio_url": "https://cdn.roasos.com/workspaces/.../line.mp3",
  "media_rights": { "accepted": true, "statement_version": 1 }
}
```

Send the block when you re-lip a real person. roasOS then writes one attestation row before it prices the request, under the purpose `lipsync` and against both the source video and the source audio, and it binds that record into the provider dispatch. This is the same machinery that the two avatar lanes use. An absent block records nothing, and it prices the request as before.

<Callout type="warn">
  The block is **optional today, and it becomes required later**. `kling-avatar-v2-pro` and `heygen-avatar-4` already require one, and VEED depicts the same thing. It is not required yet, for one reason. A person must read the consent statement before anybody accepts it. The roasOS app gains that screen in a later release. roasOS will not accept a consent that no person read, and it will not attest for you. Add the block to your VEED calls now, and the change will not reach you.
</Callout>

`sync-lipsync-v3` and `ltx-lipsync` are unchanged, and neither takes the block.

## Rule 2 — a real person needs a consent record

An attestation is a small, versioned block in the request body. roasOS writes one row for the request, and it binds that row into the provider dispatch.

```json
{
  "media_rights": { "accepted": true, "statement_version": 1 }
}
```

| Field               | Rule                                                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `accepted`          | The literal `true`. The value `false` is a `400`. On a lane that requires the block, an absent block is a `400` too. |
| `statement_version` | `1`. This is the statement that is current today. A stale version is refused.                                        |

`POST /v1/voices` takes one more field, `policy_version`, because a voice clone is stored and reused. Every other lane takes the two fields above.

### Which requests need one

| Request                                                                          | Purpose recorded | Required?                      |
| -------------------------------------------------------------------------------- | ---------------- | ------------------------------ |
| [`POST /v1/voices`](/api-reference/voices/createVoice)                           | `voice_clone`    | Required                       |
| [`POST /v1/lipsync/kling-avatar-v2-pro`](/models/lipsync/kling-avatar-v2-pro)    | `lipsync`        | Required                       |
| [`POST /v1/lipsync/heygen-avatar-4`](/models/lipsync/heygen-avatar-4)            | `lipsync`        | Required                       |
| [`POST /v1/lipsync/veed-lipsync-v2`](/models/lipsync/veed-lipsync-v2)            | `lipsync`        | Optional today; required later |
| [`POST /v1/workflows/recast`](/workflows/recast-an-actor), onto an uploaded face | `persona_swap`   | Required                       |
| Motion control, in the roasOS app                                                | `motion_control` | Required                       |

`POST /v1/workflows/recast` takes the same block as the lipsync lanes, so one shape serves the whole API.

A recast onto a roasOS gallery avatar or onto an avatar of your workspace needs **no** attestation. The gallery avatar is already licensed, and a workspace avatar was made by a person in your workspace. Send `avatar_id` for those two cases. Send no `media_rights` block with it. Send the block when the swap target is an uploaded face. An absent block then answers `400 media_rights_required`. Refer to [Recast an actor](/workflows/recast-an-actor).

### What you state when you send it

You state that you hold the written permission of the person shown, to depict them in an advertisement.

roasOS stores the record. The record cannot be edited, and no API operation deletes one. A person can revoke a consent in the roasOS app; roasOS then stops using the media that the record covers.

## What a refusal looks like

| Status | Code                                         | Cause                                                                                    |
| ------ | -------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `400`  | `discover_source_not_allowed`                | A Discover creative as the brand kit logo                                                |
| `400`  | `reference_media_not_workspace_owned`        | The media is not an immutable workspace object on `https://cdn.roasos.com`               |
| `400`  | `media_rights_required`                      | The recast target is an uploaded face and the body carries no `media_rights` block       |
| `400`  | `validation_error`                           | A model endpoint that requires the block carries none, or the statement version is stale |
| `503`  | `media_rights_attestation_store_unavailable` | roasOS could not write the consent record; nothing was priced and nothing was charged    |

A lane that treats the block as optional never answers `400` for its absence. It records nothing, and it prices the request as before.

Refer to [Errors](/concepts/errors).

## Next

* Where media comes from: [Reference media and uploads](/concepts/reference-media).
* The person swap, end to end: [Recast an actor](/workflows/recast-an-actor).
* What a static ad may render from: [Statics](/concepts/statics#rights).
