> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roughy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Asset

> An asset is a single piece of source media — audio or video you upload — scoped to one project and charged once, after it's processed.

## What is an asset

An asset is a piece of source media you upload — audio or video. It's
the thing every operation runs against: a [cut](/concepts/cut) attaches
to it, and [renders](/concepts/render) read from it. Every asset belongs
to exactly one [project](/concepts/project); listings, uploads, and
lifecycle events flow through that parent.

Cuts, subtitles, and renders are **their own entities** — not asset
types. An asset is only ever the source media.

## Types and states

| Type    | Meaning                             |
| ------- | ----------------------------------- |
| `video` | Video source you uploaded.          |
| `audio` | Audio source you uploaded directly. |

| State             | Meaning                                                                                                                                                                   |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pending_upload`  | Asset row exists; bytes are still uploading.                                                                                                                              |
| `processing`      | Upload finished; Roughy is preparing the asset (analysing it and getting it ready to cut). The per-minute charge settles here, once preparation finishes. Not usable yet. |
| `pending_payment` | Prepared, but your balance didn't cover the charge. Bytes are kept; the asset activates automatically on your next top-up.                                                |
| `ready`           | Prepared and paid for — cuttable and renderable.                                                                                                                          |
| `failed`          | Preparation permanently failed (e.g. unreadable or corrupt media); terminal. Nothing is charged. `error_code` / `error_message` carry the reason.                         |

## Billing

Roughy charges **once per source asset** — 1 credit per source minute,
rounded up (a 4 m 10 s file costs 5 credits). The charge settles **after**
the asset is processed, so a file that can't be processed is never
charged. Everything downstream (cuts, re-cuts, renders, re-renders) is
free.

A positive credit balance is required to *start* an upload
(`POST /v1/assets` rejects a zero-or-below balance with `402`). If your
balance doesn't cover the charge once processing finishes, the asset
lands in `pending_payment` (bytes retained) and activates on your next
top-up. See [Credit ledger](/concepts/credit-ledger).

## Fields

`language` is an optional hint for the spoken language of the media
(e.g. `de`); `null` auto-detects. Set once in the `POST /v1/assets` body
and **immutable** thereafter.

`script` is **not** an asset field — you supply the cut's reference
`script` per [`POST /v1/cuts`](/concepts/cut#triggering-a-cut), so the
same asset can be re-cut against a different script without re-uploading.

`type`, `content_type`, and `extension` are derived from the uploaded
bytes once the first chunk arrives — `null` before then, never
user-settable.

`size_bytes` is filled when the upload finalises; `duration_seconds` is
measured while the asset is `processing`, so it is always present by the
time the asset is `ready`.

## Reading

`GET /v1/assets/{id}` returns the asset detail; for `ready` assets it
includes a short-lived signed `download_url` and a `cuttable` boolean.
`GET /v1/assets` lists your assets newest-first — `?project_id=<id>`
narrows to one project, `?state=ready` filters by state.

## Immutability

An asset has no editable fields: `language` is set once at
`POST /v1/assets`, and everything else is derived from the bytes. There
is no `PATCH` — to change the language, delete the asset and re-upload.

## Deleting

`DELETE /v1/assets/{id}` removes the asset and everything derived from
it (cuts, subtitles, renders) via cascade — the rows disappear
immediately and the stored bytes are purged. Irreversible.

## Related concepts

* [Project](/concepts/project) — the container every asset belongs to.
* [Cut](/concepts/cut) / [Render](/concepts/render) — what attaches to an asset.
* [Credit ledger](/concepts/credit-ledger) — the per-asset charge.
