Skip to main content

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 attaches to it, and renders read from it. Every asset belongs to exactly one 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

TypeMeaning
videoVideo source you uploaded.
audioAudio source you uploaded directly.
StateMeaning
pending_uploadAsset row exists; bytes are still uploading.
processingUpload 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_paymentPrepared, but your balance didn’t cover the charge. Bytes are kept; the asset activates automatically on your next top-up.
readyPrepared and paid for — cuttable and renderable.
failedPreparation 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.

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, 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.