Anjin Media

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.

THE EXCHANGEREST · 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
}
202 ACCEPTEDx-ratelimit-remaining: 59
{ "id": "c7d2…", "status": "planning" }

Planning runs asynchronously - poll GET /v1/cuts/:id, or let cut.planned reach your webhook.

Capabilities

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 →

The surface

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.

The core API surface: endpoint, required key scope, and what each call does.
EndpointScopeWhat it does
Source groups

POST/v1/source-groups

writeCreate a group; signed upload URLs come back per file.

POST/v1/source-groups/:id/files/:fileId/complete

writeConfirm the bytes landed; ingest and transcription begin.

GET/v1/source-groups/:id/transcript

readThe diarized transcript - by segment, by word, or as captions.
Cuts

POST/v1/cuts

writeThe brief, the sources, the settings; returns 202 and starts planning.

GET/v1/cuts/:id

readCut detail with the latest plan document, verbatim.

PATCH/v1/cuts/:id/plan

writeSynchronous plan edits - remove, reorder, pin, unpin.

POST/v1/cuts/:id/revise

writeA plain-language instruction; the cut returns to planning.
Renders

POST/v1/cuts/:id/renders

writeRequest the render batch - one render per aspect.

GET/v1/cuts/:id/renders

readStatuses, signed URLs and the sidecar files.
Webhooks

POST/v1/webhook-endpoints

adminRegister an HTTPS endpoint for any of the six events; the signing secret is shown once.
Usage

GET/v1/usage

readMetered 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 →

Lifecycle

From 202 to finished file.

Nothing blocks. Create returns immediately while planning runs, and every completion or failure fires an event at your endpoint.

planningcut.plannedplannedPOST …/rendersrenderingrender.completedcomplete

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.
render.completed · one delivery
{
  "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.

Provenance

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 →

ONE COMPOSITION, DELIVEREDPER ASPECT
  • 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.
Developer ergonomics

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.

Pricing

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.

Plans and enterprise packages →

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.