API Reference

API Documentation

Everything you need to integrate Editing Machine into your applications, agents, and workflows.

Base URL: https://api.editingmachine.com/api/v1Version: v1OpenAPI Spec

Quick Start

Get up and running with the Editing Machine API in under 5 minutes. Projects follow a four-step lifecycle: create a project, attach footage, execute, then poll for status. Credits are only deducted when you execute.

1. Get your API key

Log in to your Editing Machine account and navigate to Automation → API Keys. Generate a new key and store it securely.

2. Create a project

Creating a project returns a signed price_quote — no credits are deducted yet.

Create a project
curl -X POST https://api.editingmachine.com/api/v1/projects \
  -H "Authorization: Bearer em_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_id": 1,
    "project_name": "My Video Project",
    "brand_id": 5
  }'

3. Attach footage

Attach a source file by URL
curl -X POST https://api.editingmachine.com/api/v1/projects/42/assets \
  -H "Authorization: Bearer em_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/footage.mp4" }'

4. Execute the project

Pass the quote_id from step 2 to lock in the price. Credits are deducted here.

Start execution
curl -X POST https://api.editingmachine.com/api/v1/projects/42/execute \
  -H "Authorization: Bearer em_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "quote_id": "eyJ...signed..." }'

5. Poll for status

Get project status
curl https://api.editingmachine.com/api/v1/projects/42 \
  -H "Authorization: Bearer em_xxxxxxxxxxxx"

When the status reads complete, the response includes output_urls with the finished deliverables.

Authentication

All API requests require a Bearer token in the Authorization header. API keys are scoped to your account and can be revoked at any time from the dashboard.

Header format

Authorization header
Authorization: Bearer em_xxxxxxxxxxxx

Keys are issued in the dashboard under Automation → API Keys. All keys use the single em_* format and run against live infrastructure — there is no separate test or sandbox key.

Keep keys secure

Never expose API keys in client-side code, public repos, or logs. Use environment variables and server-side requests only.

Endpoints

POST/api/v1/projects

Create a project. Returns a signed price quote — credits are not deducted yet.

Request body

recipe_idinteger*ID of a published recipe to run
project_namestringOptional human-readable name for the project
brand_idintegerOptional brand profile ID for style consistency

Response

201 Created
{
  "id": 42,
  "status": "created",
  "recipe": { "name": "YouTube Long-Form", "type": "purpose" },
  "credits_estimated": 1,
  "price_quote": {
    "quote_id": "eyJ...signed...",
    "credits": 1,
    "fingerprint": "a1b2c3...",
    "expires_at": "2026-03-25T10:15:00.000Z"
  },
  "created_at": "2026-03-25T10:00:00.000Z"
}

price_quote.quote_id is a server-signed token that locks in the price shown at creation. You must pass it to /execute. Tampered, expired, or stale quotes (pricing has drifted) are rejected — re-create the project to get a fresh one.

POST/api/v1/projects/:id/assets

Attach source footage to a project by URL. Returns immediately while the file imports in the background.

Request body

urlstring*Publicly accessible URL of the source video or image file

Response

202 Accepted
{
  "asset_id": "import-a1b2c3d4",
  "filename": "footage.mp4",
  "status": "importing",
  "size_bytes": null
}
POST/api/v1/projects/:id/execute

Start the project. Credits are deducted here. Project must be in created or draft status.

Request body

quote_idstring*The signed quote_id returned from project creation

Response

200 OK
{
  "id": 42,
  "status": "queued",
  "credits_deducted": 1,
  "credits_remaining": 14
}
GET/api/v1/projects/:id

Poll a project's current status, progress, and output URLs.

200 OK
{
  "id": 42,
  "status": "processing",
  "progress_percent": 65,
  "output_urls": [],
  "created_at": "2026-03-25T10:00:00.000Z",
  "updated_at": "2026-03-25T10:30:00.000Z"
}

Status values

createdprocessingcompleterevisionfailed

Webhooks

Receive real-time notifications when project status changes. Register an endpoint with POST /api/v1/webhooks specifying the URL and events you want to subscribe to.

Register a webhook

POST /api/v1/webhooks
{
  "url": "https://your-app.example.com/webhooks/editing-machine",
  "events": [
    "project.started",
    "project.completed",
    "project.failed",
    "project.awaiting_client_input"
  ]
}

Event types

project.startedExecution has begun on the project
project.completedProject is finished. output_urls is populated with deliverables
project.failedExecution failed. Error details included in the payload
project.awaiting_client_inputThe Director needs the client to respond before continuing

Example payload

POST to your registered URL
{
  "event": "project.completed",
  "project_id": 42,
  "timestamp": "2026-03-25T12:00:00.000Z",
  "data": {
    "status": "complete",
    "output_urls": ["https://..."]
  }
}

Signature verification

Every webhook request includes a signature header so you can verify it came from Editing Machine:

Signature header
X-Webhook-Signature: <hex HMAC-SHA256 of the raw request body>

The value is a raw HMAC-SHA256 hex digest of the request body using your webhook secret — no sha256= prefix. Your secret is shown in the dashboard alongside your API keys. Always verify signatures before processing webhook data.

Status Codes

200
OK — Request succeeded
201
Created — Resource created successfully
202
Accepted — Request accepted for asynchronous processing
400
Bad Request — Invalid body or parameters
401
Unauthorized — Missing, invalid, or expired API key
402
Payment Required — Insufficient credits
404
Not Found — Resource not found or not owned by your account
409
Conflict — Project already executing/completed, or quote_stale (pricing drifted since the quote was issued)
410
Gone — quote_expired (signed quote is past its expires_at; re-create the project)
429
Too Many Requests — Rate-limit or concurrent-job limit exceeded
500
Internal Server Error — Something went wrong on our end

Error response format

Errors are returned as a flat object with a machine-readable code and a human-readable message:

Error response
{
  "error": "quote_expired",
  "message": "Price quote expired. Re-create the project to get a fresh quote."
}

Rate limits

Rate limits are per API key and tiered by plan. Concurrent jobs are also capped — projects beyond your limit will return 429 until one finishes.

Tier
Requests/min
Concurrent Jobs
Free
5
1
LITE
15
3
PLUS
30
5
PRO
60
10

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.

Source of truth

The live OpenAPI spec is generated directly from server code and kept in sync by a CI drift check. If anything here disagrees with the spec, the spec is right.

Ready to start building?

Get your API key and run your first project in minutes.