Morpha API

Morpha is an AI-driven video editor for short-form social video. You arrange layered elements — video clips, images, text, shapes — over a composition, animate them on a 30 fps keyframe timeline, and export an MP4. The editor runs in the browser; this site documents the programmatic API that drives the same projects from outside the editor.

What the API is for

Every project Morpha can edit in the browser, an external agent can edit over the network. The recommended way in is the npm SDK; beneath it are two raw protocol surfaces — all driving the same tool catalog:

They all call the same pure dispatch layer, so behaviour is identical whichever you use. A tool call loads the project from storage, applies the change, validates it against the schema, and writes it back.

The API is built for the work a person would never click through by hand: "place 50 stars at random positions, each with a staggered fade-in", "duplicate this layer 30 times in a circle", "recolour every shape along a gradient". One described instruction, hundreds of mutations.

Quickstart

The whole loop, in order — each step is detailed in its own section below.

  1. Get a key. No account, no browser, nobody to ask? Morpha gives agents an anonymous account for exactly this. Register one from code:

bash curl -sX POST https://morphareels.ai/api/auth/agent-register # → {"token":"mp_…","claimUrl":"https://morphareels.ai/claim/…"}

The SDK wraps registration as registerAccount(). The key goes in the Authorization: Bearer header on every call, whether over HTTP, through the SDK, or from an MCP client configured with that header. The account holds 1 project and has no AI credit envelope, so drive the tool catalog with your own model, which is free and unmetered. Step 6 hands the work to a person with the claimUrl; an anonymous account nobody claims is deleted after 30 days.

If there is a human with an account: sign your MCP client in (in Claude Code, from the /mcp menu; see Connecting over MCP, below), or sign in at morphareels.ai/app, open /app/settings, and mint a key by hand. Either way it looks like mp_…, is shown once, and goes in MORPHA_API_KEY (see Authentication, below).

  1. Connect. SDK: npm i morphareels-sdk, then createClient({ token: process.env.MORPHA_API_KEY }). Or MCP: the URL above. Both call the same tool catalog.
  2. Pick a project. list_projects() returns { id, name, editorUrl }; the id is the projectId every other tool takes (refer to projects by name with the user, never the id).
  3. Browse before you touch. describe_video(projectId) returns the layer tree — read every element id from there, never invent one. Pull inspect_layers([elementId]) only for the layers you'll change.
  4. Mutate, then save. Call your mutating tool(s), then save_version(projectId, name="short label").
  5. Render, and hand it back. client.renderVideo(projectId) returns the MP4 as a Buffer, encoded by a real local browser on macOS or Windows — free, any length. client.renderVideoToFile(projectId, path) writes it to disk instead, for a long video. With no browser to drive, a subscriber's agent calls render_video over MCP or HTTP instead and Morpha renders it on its own container, charged to the subscription's credits; render_status returns the download link. If you registered an anonymous account in step 1, give the person its claimUrl as well as the file. They open it, sign in or sign up as themselves, and the project moves into their own account, editable.

New here? [Getting started](/docs/getting-started) covers the conventions you must internalise — centre-anchored coordinates, frames vs seconds, and why you never invent an element id.

npm i morphareels-sdk
import { createClient } from "morphareels-sdk";

const morpha = createClient({ token: process.env.MORPHA_API_KEY }); // origin defaults to https://morphareels.ai

const tools = await morpha.listTools();
const project = await morpha.getProject("your-project-id");
const { result, project: next, editorUrl } = await morpha.callTool(
  "your-project-id",
  "describe_video",
  {},
);

createClient talks to the same Worker endpoints as MCP (GET /api/project/:id, GET /api/tools, POST /api/tool/:name); callTool does the load → dispatch → write round-trip server-side. It also renders a composited PNG frame with renderFrame, or the full composition to MP4 with renderVideo (no ffmpeg, no server — a real local browser does the encode). For local dev, createClient({ origin: "http://localhost:8787" }) needs no token. Full reference: the [SDK page](/docs/sdk).

Connecting over MCP

Point your client at the URL and sign it in: every tool call needs a signed-in connection. Morpha is an OAuth 2.1 authorization server for its own /mcp, so a client that follows the MCP authorization spec has you sign in (or create a free account right there), you approve the client, and it receives a key. In Claude Code you sign in from the /mcp menu before the agent calls a tool, because Claude Code answers a call with no key by disconnecting the server. The MCP page has the detail. There is nothing to paste:

{
  "mcpServers": {
    "morpha": {
      "type": "http",
      "url": "https://morphareels.ai/mcp"
    }
  }
}

In Claude Code that is one command:

claude mcp add --transport http morpha https://morphareels.ai/mcp

The key it receives is an ordinary mp_… key. It appears in `/app/settings` named after the client that asked for it, works with the SDK and the HTTP API too, and you revoke it there like any other. If your client cannot sign in, mint a key yourself and send it as a header instead:

{
  "mcpServers": {
    "morpha": {
      "type": "http",
      "url": "https://morphareels.ai/mcp",
      "headers": { "Authorization": "Bearer mp_your_api_key_here" }
    }
  }
}

For local development against wrangler dev, point at http://localhost:8787/mcp — no auth header is needed in dev (ENVIRONMENT=development bypasses the auth gate).

Connecting over HTTP

The HTTP base URL is https://morphareels.ai.

curl -X POST https://morphareels.ai/api/tool/describe_video \
  -H "Authorization: Bearer mp_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "your-project-id", "args": {} }'

Authentication

The SDK, MCP, and HTTP all use the same credential: a bearer API key. A person gets one in either of the two ways below, and both produce the same thing. An agent with no person to sign in gets one from POST /api/auth/agent-register or the SDK's registerAccount() (see Quickstart), and sends it as Authorization: Bearer like any other key.

Sign in from your MCP client. Point it at https://morphareels.ai/mcp with no header and sign it in; in Claude Code that is the /mcp menu. The client discovers the authorization server and has you sign in. A free account is enough, and you can create one on the spot. Approve the client and it holds a key from then on.

Or mint one by hand, which is what the SDK and raw HTTP need:

  1. Sign in to the editor at morphareels.ai/app. MCP and the API are included with every plan, without a per-call charge.
  2. Open `/app/settings` and mint an API key. It looks like mp_… and is shown once — copy it immediately.
  3. Use it: createClient({ token: "mp_…" }) with the SDK, or send Authorization: Bearer mp_… on every MCP or HTTP request.

Keys are revocable from the same settings page. Each key maps to your account, so a tool call sees exactly the projects you'd see in the editor. Your plan sets three limits. Storage is 1 GB on the free plan: an upload that would exceed it comes back as a 402 naming the figures, and nothing already stored is touched. The free plan also holds up to 5 projects, and a paid plan holds any number. And one uploaded clip may be up to 500 MB on the free plan and 10 GB on a paid plan. A clip counts toward storage together with the preview proxy the editor plays, so it is refused at upload when both would not fit. In local wrangler dev the auth gate is bypassed entirely — no key required (createClient({ origin: "http://localhost:8787" })).

Where to go next

When the person you are working for needs help with their account, billing or a project, send them to Support, which gives the contact address.