Video composition API
An editorial
instruction in.
A rendered edit out.
One POST carries the brief, the sources it may draw on and the formats to ship. Back comes a cut plan you can read, edit and revise - then a finished edit whose every segment names its source and timecodes.
A video composition API, not a clipping endpoint: several moments from across your footage, ordered to carry one argument, with nothing generated.
The full workflow - sources, brief, plan, render - over REST and MCP.
POST /v1/cuts
authorization: Bearer mk_live_9a4f…
idempotency-key: 8d41…
{
"prompt": "The clearest answer we gave on data residency",
"source_group_ids": ["9f4b…"],
"settings": { "target_duration_s": 45 },
"aspects": ["9:16"],
"auto_render": true
}{ "id": "c7d2…", "status": "planning" }Planning runs asynchronously - poll GET /v1/cuts/:id, or let cut.planned reach your webhook.
The whole workflow, on the wire.
Sources in, brief in, plan reviewed, edit out - the same engine the app uses, addressed as an API.
Briefed, not keyframed
One request carries the prompt - up to 2,000 characters - the source groups it may draw from, and the settings that shape the edit: duration, tolerance, pace, chronology.
Plan before spend
Planning returns a document, not a file. Read it, strike a segment, pin another, or revise the whole thing in plain language - the render is a separate, deliberate step.
Every format
Up to three aspects per cut - 16:9, 1:1 and 9:16 at 1920×1080, 1080×1080 and 1080×1920 - rendered from the same plan. Set auto_render and the first plan goes straight to render.
The footage, addressable
Sources are transcribed and diarized on ingest. Fetch the transcript, list who spoke and for how long, and give speakers display names.
Push, not poll
Six webhook events cover ingest, planning and rendering. Deliveries are signed and retried with backoff, so your pipeline hears about state changes instead of asking.
Agents included
The same service is exposed as thirteen MCP tools, so an agent composes edits the way your code does - same validation, same lifecycle, same files.
The quickstart walks the loop end to end - upload, brief, plan, render - start there →
Eleven calls cover it.
The core of the API, path for path. Reads are quiet, writes carry the accent, and nothing here is invented - these are the routes the platform serves today.
| Endpoint | Scope | What it does |
|---|---|---|
| Source groups | ||
POST | write | Create a group; signed upload URLs come back per file. |
POST | write | Confirm the bytes landed; ingest and transcription begin. |
GET | read | The diarized transcript - by segment, by word, or as captions. |
| Cuts | ||
POST | write | The brief, the sources, the settings; returns 202 and starts planning. |
GET | read | Cut detail with the latest plan document, verbatim. |
PATCH | write | Synchronous plan edits - remove, reorder, pin, unpin. |
POST | write | A plain-language instruction; the cut returns to planning. |
| Renders | ||
POST | write | Request the render batch - one render per aspect. |
GET | read | Statuses, signed URLs and the sidecar files. |
| Webhooks | ||
POST | admin | Register an HTTPS endpoint for any of the six events; the signing secret is shown once. |
| Usage | ||
GET | read | Metered usage for any period - ingest, planning, rendered minutes, storage, egress. |
BASE URL https://anjin-media-api.fly.dev
The full surface - brand kits, speakers, plan versions, deletes - with every schema and error code, is in the API reference →
From 202 to finished file.
Nothing blocks. Create returns immediately while planning runs, and every completion or failure fires an event at your endpoint.
If planning or a render fails, cut.failed or render.failed fires instead - and a revise returns any cut to planning for another pass.
The six events
source.readyA source group finished ingest; its footage is addressable.source.failedIngest did not complete for a source group.cut.plannedThe plan is ready to read, edit and revise.cut.failedPlanning did not produce a plan.render.completedA render finished - aspect, duration and QC result attached.render.failedA render did not complete.
{
"event": "render.completed",
"account_id": "a1f0…",
"ids": { "cut_id": "c7d2…", "render_id": "r3a9…" },
"summary": {
"aspect": "9:16",
"duration_ms": 44800,
"qc_passed": true,
"render_seconds": 38.2
},
"occurred_at": "2026-08-17T14:03:21Z"
}Every delivery is signed - anjin-signature: t=…,v1=…, an HMAC-SHA256 with the secret only you hold - and delivered at-least-once with backoff, so verify, then de-duplicate.
Every second, accounted for.
A composition starts as a plan document: an ordered list of segments, each naming its source and its source timecodes. The plan is the contract you approve - and every version of it is kept, whether the planner wrote it, a revision produced it, or you edited it by hand.
The render honours that plan and ships with its working attached: captions, an edit decision list and a QC report ride alongside the file, fetched from the same call as the signed URL.
Where the media sits while all this happens - storage, processing, sub-processors - is written down plainly on the security page →
- PLAN · JSONThe cut planEvery segment names its source and the timecodes it was lifted from - kept at every version.
- MP4The editRendered per aspect you requested.
- SRT · VTTCaptionsTimed to the finished edit - SubRip and WebVTT.
- EDL · JSONEdit decision listSegment order, sources and timecodes, machine-readable - ready for a conform or an audit.
- QCQuality reportThe checks the render passed, alongside the file.
The parts you only notice when they're missing.
authorization: Bearer mk_live_9a4f…
Bearer keys, scoped
Keys are minted in the dashboard and shown once. Scope each one read, write or admin - a reporting job never needs the key that can delete.
{
"type": "https://anjin.media/errors/group_not_ready",
"title": "Group Not Ready",
"status": 422,
"detail": "groups not ready: 9f4b…",
"code": "group_not_ready"
}Errors you can program against
Every failure is RFC 9457 problem+json: a stable code to switch on, a type URL that documents it, and a retry-after header when waiting is the fix.
idempotency-key: 8d41… idempotency-replayed: true
Retries that are safe
Send an idempotency-key on any request that creates something. A network retry replays the stored response - flagged idempotency-replayed - instead of creating a second cut.
x-ratelimit-remaining: 59 retry-after: 12
Limits you can see
60 requests a minute per key, 120 per account. The remaining budget rides on every authenticated response, so back-pressure is a header read, not a guess.
Priced by the source minute.
Source minutes are counted once, when a source group is ingested. Creating a cut, reading its plan, revising it and rendering it use none. Paid plans start at £39 a month for 240 source minutes.
Questions
- How do I get an API key?
- Keys are minted in the dashboard under Settings → API keys - sign in, create a key, and the raw value is shown once. Each key carries the scopes you give it (read, write or admin), and you can revoke it at any time.
- Is creating a cut synchronous?
- No. POST /v1/cuts returns 202 with the cut's id while planning runs. Poll GET /v1/cuts/:id, or register a webhook and cut.planned will tell you the moment the plan is ready to read.
- Can I change the plan before rendering?
- Yes - that is the design. PATCH the plan to remove, reorder or pin segments synchronously, or POST a revision in plain language and a new plan version comes back. Rendering is a separate, explicit request, so nothing spends until you ask for the file.
- How are webhook deliveries verified?
- Every delivery carries an anjin-signature header: a timestamp and an HMAC-SHA256 of the payload, computed with the endpoint secret you were shown at registration. Verify with a constant-time compare and a short tolerance window. Delivery is at-least-once with backoff, so handlers should de-duplicate.
- What are the rate limits?
- 60 requests a minute per key and 120 per account. Every authenticated response carries x-ratelimit-remaining, and a 429 includes retry-after. Give any request that creates something an idempotency-key header and its retries are safe to repeat.
- Can an agent use this without writing REST calls?
- Yes. The platform exposes the same service over MCP - thirteen tools covering the workflow from listing source groups to rendering a cut - so an agent can compose edits as a step in its own work. REST and MCP behave identically because they call the same code.
One request away.
The full workflow - sources, brief, plan, render - over REST and MCP.
