Automate Video Creation with the Wavemaker API
A practical guide to generating, rendering, and downloading video programmatically with the Wavemaker REST API — endpoints, auth, the generate→render flow, webhooks vs polling, and a copy-paste script.
If you generate video regularly — per-product ads, weekly recaps, localized cuts — doing it by hand doesn’t scale. The Wavemaker REST API lets you generate, render, and download finished video from your own code, a backend job, or CI. This guide walks the whole flow with runnable examples.
Authentication
Create an API key in the dashboard at /keys (you’ll need a plan with API access). Every request carries it as a Bearer token:
Authorization: Bearer mcp_your_api_key
Content-Type: application/json
The base URL is https://api.wavemakr.com. Errors come back as { "error": "<message>" } with a meaningful status (400 invalid input, 402 insufficient credits, 403 wrong scope, 404 not found / not yours).
The core flow: generate → render → download
Four steps take you from a brief to an MP4:
- Start a generation —
POST /api/v1/videos - Wait for it — poll
GET /api/v1/videos/:job_id(or use a webhook) untilcomplete; it returns acomposition_id - Render to MP4 —
POST /api/v1/renderswith thatcomposition_id - Download — poll
GET /api/v1/renders/:render_iduntildone; use thedownload_url
1. Start a generation
curl -X POST https://api.wavemakr.com/api/v1/videos \
-H "Authorization: Bearer $WAVEMAKR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "30s vertical ad for Driftwood Coffee cold brew, upbeat, end on driftwood.com",
"aspect_ratio": "9:16",
"duration_seconds": 30
}'
# → 202 { "job_id": "wf_..." }
Optional body fields: skill_type (a treatment id from GET /api/v1/treatments), model_overrides (per-run model pins from GET /api/v1/models), and webhook_url / webhook_secret.
2–4. The whole loop in Node (zero dependencies)
const BASE = "https://api.wavemakr.com";
const KEY = process.env.WAVEMAKR_API_KEY;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function api(method, path, body) {
const res = await fetch(`${BASE}${path}`, {
method,
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json();
if (!res.ok) throw new Error(`${method} ${path} → ${res.status}: ${json.error}`);
return json;
}
// 1. generate
const { job_id } = await api("POST", "/api/v1/videos", {
prompt: "30s vertical ad for Driftwood Coffee, end on driftwood.com",
aspect_ratio: "9:16",
duration_seconds: 30,
});
// 2. poll until complete
let compositionId;
for (;;) {
await sleep(10_000);
const s = await api("GET", `/api/v1/videos/${job_id}`);
if (s.status === "complete") {
compositionId = s.composition_id;
break;
}
if (s.status === "errored") throw new Error(s.error);
}
// 3. render
const { render_id } = await api("POST", "/api/v1/renders", { composition_id: compositionId });
// 4. poll render, get the MP4
let downloadUrl;
for (;;) {
await sleep(5_000);
const r = await api("GET", `/api/v1/renders/${render_id}`);
if (r.status === "done") {
downloadUrl = r.download_url;
break;
}
if (r.status === "failed") throw new Error(r.error);
}
console.log("MP4:", downloadUrl);
Prefer webhooks in production
Polling is fine for a script, but in a real backend pass a webhook_url. On completion Wavemaker POSTs a JSON event (video.completed, render.completed, …). Provide a webhook_secret and verify the X-Webhook-Signature: v1,<hmac-sha256> header before trusting the payload. Webhook URLs must be HTTPS and carry no credentials.
Estimate cost before you generate
POST /api/v1/cost-estimates returns a credit estimate from rough inputs (scene_count, video_clips, ai_images, wants_voiceover, has_url, has_topic) — useful for budgeting a batch. GET /api/v1/account returns your current balances.
Edit without regenerating
The pipeline reviews every scene as it generates. GET /api/v1/videos/:job_id/reviews returns those per-scene verdicts (status, score, issues, recommended action) for free — no re-review. To fix something, POST /api/v1/videos/:composition_id/refine with a natural-language instruction (“scene 3 has a third arm — regenerate it”). For structured, identity-preserving edits, pull the composition into a workspace and call targeted tools.
Useful catalogs
GET /api/v1/treatments— validskill_typevalues (formats/styles).GET /api/v1/models— validmodel_overridesvalues.GET /api/v1/brand-kits— brand kit ids to seed brand context.
Beyond single videos
For per-scene control, identity-locked characters, and custom chains, see the workspace tools and the end-to-end automation guide. Prefer working from an AI assistant? Connect Wavemaker over MCP.
Full endpoint reference lives in the developer docs. Grab an API key and build →
Frequently asked questions
- Does Wavemaker have an API?
- Yes. Wavemaker exposes a REST API at https://api.wavemakr.com (API-key auth) and an MCP endpoint at https://api.wavemakr.com/mcp. The REST API covers managed generation, refinement, rendering, reviews, compositions, uploads, catalogs, and account/billing.
- How do I generate a video via the API?
- POST /api/v1/videos with a prompt (and optional aspect_ratio, duration_seconds, skill_type) and a Bearer API key; you get back a job_id. Poll GET /api/v1/videos/:job_id until status is complete (it returns a composition_id), then POST /api/v1/renders to produce an MP4.
- Should I poll or use webhooks?
- Use webhooks in production. Pass a webhook_url (and webhook_secret to verify the HMAC signature) on generation and render requests; you'll get a POST when the job completes instead of polling.
- How do I get an API key?
- Create one in the dashboard at /keys (requires a plan with API access). Keys begin with mcp_ and go in the Authorization: Bearer header.