You give the platform video - uploaded directly or pulled from a URL you control. It transcodes each file, transcribes it with word-level timing and labels who is speaking. You then describe the edit you want in plain language, along with a target duration and the aspect ratios you need. The planner selects passages from across that footage, orders them into one argument and returns a plan you can read, edit and revise before anything renders. Every segment in that plan names the source it came from and the timecodes it was lifted from, so nothing in a finished edit is generated - it is your own footage, re-ordered.
Two ways in#
The REST API and the MCP server are the same service. Both call the same validation, produce the same lifecycle and write the same files - pick the one that matches who is doing the work.
Your code calls the API
Use REST when a backend of yours drives the workflow: create a source group, wait for it to become ready, post a brief, read the plan, request renders, collect the signed URLs. The quickstart walks that loop end to end in curl, TypeScript and Python, and the API overview covers what it is for.
An agent calls the tools
Use MCP when an agent is doing the work. The server is mounted at https://anjin-media-api.fly.dev/mcp over streamable HTTP and exposes thirteen tools covering the same workflow, with per-tool scope checks against the same bearer key. See MCP & agents for the tool list and the canonical agent loop, or the MCP overview for what an agent can do with it.
Base URL and auth#
Every REST path below is relative to one host, and it is the one the platform actually serves:
https://anjin-media-api.fly.dev
Authenticate with a bearer token. Keys are prefixed mk_live_ followed by 48 hexadecimal characters, and carry any combination of the read, write and admin scopes:
curl -sS https://anjin-media-api.fly.dev/v1/source-groups \ -H "authorization: Bearer $ANJIN_API_KEY"
A key that does not resolve gets 401 invalid_api_key; a key that resolves but lacks the scope a route needs gets 403 insufficient_scope. Every authenticated response - success or failure - carries an x-ratelimit-remaining header. Read Authentication for scopes, key hygiene and the rate limits.
Errors are RFC 9457 problem documents with the content type application/problem+json. Each one carries a stable code you can switch on, and never a nested error object.
The async model#
Nothing that costs time blocks. Ingest, planning and rendering all happen in workers, so the call that starts them returns immediately with a status you can track:
| Call | Status | What happens |
|---|---|---|
POST /v1/source-groups | 201 | Creates the group and returns a signed upload URL for every file you named with filename. A file given a source_url starts ingesting straight away. |
POST /v1/source-groups/:id/files/:fileId/complete | 202 | Confirms one upload. The group moves to ingesting and the transcode, transcription and diarization jobs are queued. |
POST /v1/cuts | 202 | Returns { "id": …, "status": "planning" } while the planner reads your transcripts and writes a cut plan. |
POST /v1/cuts/:id/revise | 202 | Sends a plain-language instruction and puts the cut back into planning for a new plan version. |
POST /v1/cuts/:id/renders | 202 | Queues one render per aspect you asked for and returns their ids immediately. |
Each of the three long-running objects has its own status enum, and a GET on the object tells you where it got to:
| Object | States | Progression |
|---|---|---|
source group | 5 states | uploading → ingesting → perceiving → ready, or failed. Only a ready group can be used in a cut. |
cut | 5 states | planning → planned → rendering → complete, or failed. A revision returns a cut to planning. |
render | 4 states | queued → processing → complete, or failed. One render row per aspect. |
Poll, or be told
Polling a GET is the simplest thing that works, and it is what the quickstart does. For anything long-running, register an HTTPS endpoint instead and let the platform tell you. There are exactly six events:
source.readysource.failedcut.plannedcut.failedrender.completedrender.failed
Deliveries are signed with an anjin-signature header and retried with backoff. Webhooks covers registration, verification and delivery behaviour.
Every page#
Where to go next, in reading order.
Get started
- Quickstart - Account to first rendered edit, fastest path.
- Authentication - API keys, environments, secret handling.
Working with media
- Uploading video - Uploads, source URLs, limits, persistent assets.
- Creating a composition - Prompt, source selection, duration, aspect, output.
- Composition results - Job states, output URLs, segments, transcript, provenance.
- Webhooks - Signed completion, failure and retry events.
- Working with an archive - Enterprise indexing, library queries, cross-video composition.
Agents & reference
- MCP & agents - Connection, tools, permissions, example agent prompts.
- Errors & limits - Status codes, rate limits, retries, idempotency.
- Security & data handling - Retention, training policy, data boundaries.
- API reference - Complete endpoint and schema reference.
The shape of the work is the same whichever path you take: brief, plan, review, render. Structural edits to a plan - PATCH /v1/cuts/:id/plan to remove, reorder, pin or unpin entries - run synchronously with no planner call and are free; a revision re-runs the planner for a new version; a render produces the finished file.
If you are still deciding whether this fits your work rather than how to wire it up, the API overview and the MCP overview make the case in fewer words, and pricing is where the commercial model lives.
