Home / Developers
APIMCPWebhooksBuild with Meo Studio
Generate AI videos and images from your own app, scripts or AI assistant. One API key gives you a REST API and a remote MCP server for Claude, Cursor and other agents, on the same credits as the studio.
1. Get an API key
Sign in, open the account menu (your initial, top right) and choose API & MCP. Create a key and copy it: it starts with meo_live_ and is shown once, with a webhook signing secret. The API works on any active plan and spends that plan's credits, exactly like the studio.
2. Quickstart
Make a 5-second Kling 3.0 video and wait up to 55 seconds for it:
curl https://www.mymeo.app/v1/generations \
-H "Authorization: Bearer $MEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-3",
"prompt": "A red vintage sports car drifts around a wet mountain curve at dusk, low tracking shot",
"params": { "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" },
"wait_seconds": 55
}'
If it isn't finished yet you get status queued or processing. Poll GET /v1/generations/{id}?wait=55 or pass a webhook_url. When it completes, outputs[0].url is your file.
// Node 18+ / Deno / Bun
const res = await fetch("https://www.mymeo.app/v1/generations", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.MEO_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ model: "soul-2", prompt: "Editorial portrait in soft window light", params: { aspect_ratio: "4:5" }, wait_seconds: 30 }),
});
const gen = await res.json();
console.log(gen.status, gen.outputs?.[0]?.url);
import os, requests
H = {"Authorization": f"Bearer {os.environ['MEO_API_KEY']}"}
gen = requests.post("https://www.mymeo.app/v1/generations", headers=H, json={
"model": "seedance-2", "prompt": "A lone surfer at golden hour, slow tracking shot",
"params": {"resolution": "720p", "duration": 5}}).json()
while gen["status"] in ("queued", "processing"):
gen = requests.get(f"https://www.mymeo.app/v1/generations/{gen['id']}?wait=55", headers=H).json()
print(gen["status"], gen["outputs"][0]["url"] if gen["outputs"] else gen["error"])
Animate your own photo: upload it first, then pass the returned URL as image_url.
curl https://www.mymeo.app/v1/uploads -H "Authorization: Bearer $MEO_API_KEY" -H "Content-Type: image/jpeg" --data-binary @photo.jpg
# → {"url":"https://www.mymeo.app/uploads/…/abc.jpg"}
3. MCP server for AI assistants
Let Claude, Cursor or any MCP client make images and videos for you. The server speaks Streamable HTTP at https://www.mymeo.app/mcp and authenticates with your API key. Tools: list_models, get_model, estimate_cost, create_generation, get_generation, list_generations, cancel_generation, list_templates, get_account.
Claude Code
claude mcp add --transport http meo https://www.mymeo.app/mcp --header "Authorization: Bearer meo_live_…"
Claude Desktop (Settings → Developer → Edit config)
{
"mcpServers": {
"meo": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://www.mymeo.app/mcp", "--header", "Authorization: Bearer meo_live_…"]
}
}
}
Cursor, Windsurf, VS Code (mcp.json)
{
"mcpServers": {
"meo": { "url": "https://www.mymeo.app/mcp", "headers": { "Authorization": "Bearer meo_live_…" } }
}
}
Apps that can't send headers can use https://www.mymeo.app/mcp/k/meo_live_…. Treat that URL like a password.
Then just ask: "Make a 5-second cinematic drone shot of Tokyo at night with Kling 3.0 and give me the link."
4. Endpoints
| Endpoint | What it does |
|---|---|
| GET /v1/account | Plan and credits left |
| GET /v1/models | Every model with modes, settings (params) and credits per quality. Filter with ?kind=video|image |
| GET /v1/models/{id} | One model |
| POST /v1/estimate | Credits a request would cost: {"model","params","video_seconds"} |
| GET /v1/templates | Motion templates (need image_url) and clip templates (need image_urls). ?kind=motion|clip&search= |
| POST /v1/generations | Start a generation. Optional Idempotency-Key header, webhook_url, wait_seconds (max 55) |
| GET /v1/generations | Your generations, newest first. ?limit=&starting_after= |
| GET /v1/generations/{id} | Status and outputs. ?wait=55 long-polls |
| POST /v1/generations/{id}/cancel | Cancel and refund |
| POST /v1/uploads | Upload an image or video (raw body, up to 200 MB). Uploads are deleted after 72 hours |
Request body for POST /v1/generations: model (video: genjutsu, seedance-2, seedance-2-5, kling-3, minimax-h3, wan-3-prime…; image: soul-2, soul-standard, marketing-studio, grok-imagine-2, ideogram-4…), prompt, params (keys from the model's params list, such as resolution, duration, aspect_ratio), and optionally image_url, image_urls, video_url + video_seconds, template_id. The mode (text, image or video to video) is picked from the inputs; set mode to override. Statuses: queued, processing, completed, failed, canceled. Download outputs soon: provider links can expire.
5. Webhooks
Pass webhook_url (public https) and we POST the finished generation there as {"type":"generation.completed"|"generation.failed"|"generation.canceled","data":{…}}. Failed deliveries are retried 6 times with backoff. Verify the Meo-Signature: t=…,v1=… header with your key's webhook secret:
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
6. Limits and errors
- 120 requests a minute per key, 20 new generations a minute, and your plan's number of generations running at once (Starter 2, Creator 4, Studio 8).
- Credits are taken when a generation starts and refunded automatically if it fails, is blocked or is cancelled while queued.
- Errors return a status code and
{"error":"message"}: 400 bad input, 401 bad key, 402 no plan or not enough credits, 404 not found, 409 can't cancel, 429 slow down, 503 paused. - Up to 10 keys per account. Revoke a key any time from the account menu.
Questions or need higher limits? Contact us.