Render demo videos programmatically via the Democut REST API. Available on the Scale plan.
https://democut.dev/apiAll API requests require an Authorization header with your API key. Find your key in the dashboard under Settings → API.
Authorization: Bearer dk_live_xxxxxxxxxxxxxxxxxxxxxxxx| Plan | Renders/month | Concurrent renders |
|---|---|---|
| Free | 3 | 1 |
| Pro | 50 | 3 |
| Scale | Unlimited | 10 |
Rate limit headers: X-RateLimit-Remaining and X-RateLimit-Reset are included in all responses.
/api/renderStart a new video render. Returns immediately with a render ID that you can poll for status.
| Field | Type | Required | Description |
|---|---|---|---|
| template_id | string | Yes | Template identifier (see templates below) |
| input_data | object | Yes | Template-specific input data (see schema below) |
| webhook_url | string | No | URL to POST when render completes |
{
"id": "rnd_a1b2c3d4e5f6",
"status": "queued",
"template_id": "app-showcase",
"created_at": "2026-03-21T10:00:00Z"
}/api/render/{id}Check the status of a render job. Poll this endpoint until status is done or failed. Recommended poll interval: 2 seconds.
{
"id": "rnd_a1b2c3d4e5f6",
"status": "done",
"template_id": "app-showcase",
"output_url": "https://democut.dev/renders/rnd_a1b2c3d4e5f6.mp4",
"created_at": "2026-03-21T10:00:00Z",
"completed_at": "2026-03-21T10:00:08Z"
}Status values: queued · rendering · done · failed
/api/templatesList all available templates and their required input schemas.
{
"templates": [
{
"id": "app-showcase",
"name": "App Showcase",
"description": "Animated screenshots with feature callouts",
"duration_seconds": 6
},
{
"id": "feature-announcement",
"name": "Feature Announcement",
"description": "New feature reveal with motion graphics",
"duration_seconds": 5
},
{
"id": "onboarding-welcome",
"name": "Onboarding Welcome",
"description": "Personalized welcome video with user data",
"duration_seconds": 4
}
]
}ID: app-showcase · 6 seconds · 1080p
{
"app_name": "string", // Your app name (required)
"tagline": "string", // Short tagline (required)
"features": ["string"], // Up to 4 feature bullet points (required)
"screenshot_url": "string", // HTTPS URL to a screenshot image (required)
"primary_color": "string" // Hex color, e.g. "#4d6fff" (optional, default: #4d6fff)
}ID: feature-announcement · 5 seconds · 1080p
{
"app_name": "string", // Your app name (required)
"feature_name": "string", // Name of the new feature (required)
"feature_description": "string", // One-sentence description (required)
"badge_text": "string", // Badge label, e.g. "New" or "v2.0" (optional)
"primary_color": "string" // Hex color (optional, default: #4d6fff)
}ID: onboarding-welcome · 4 seconds · 1080p
{
"app_name": "string", // Your app name (required)
"user_name": "string", // Recipient's first name (required)
"welcome_message": "string", // Custom welcome line (optional)
"cta_text": "string", // Call-to-action button label (optional, default: "Get started")
"primary_color": "string" // Hex color (optional, default: #4d6fff)
}# Start a render
curl -X POST https://democut.dev/api/render \
-H "Authorization: Bearer dk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"template_id": "app-showcase",
"input_data": {
"app_name": "Acme CRM",
"tagline": "Close deals faster.",
"features": ["Pipeline management", "Email integration", "Analytics"],
"screenshot_url": "https://example.com/screenshot.png"
}
}'
# Check status
curl https://democut.dev/api/render/rnd_a1b2c3d4e5f6 \
-H "Authorization: Bearer dk_live_xxxxxxxxxxxxxxxxxxxxxxxx"const API_KEY = "dk_live_xxxxxxxxxxxxxxxxxxxxxxxx";
const BASE_URL = "https://democut.dev/api";
async function renderDemo(inputData) {
// Start render
const res = await fetch(`${BASE_URL}/render`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
template_id: "app-showcase",
input_data: inputData,
}),
});
const { id } = await res.json();
// Poll for completion
while (true) {
await new Promise((r) => setTimeout(r, 2000));
const status = await fetch(`${BASE_URL}/render/${id}`, {
headers: { "Authorization": `Bearer ${API_KEY}` },
}).then((r) => r.json());
if (status.status === "done") return status.output_url;
if (status.status === "failed") throw new Error("Render failed");
}
}
const url = await renderDemo({
app_name: "Acme CRM",
tagline: "Close deals faster.",
features: ["Pipeline management", "Email integration", "Analytics"],
screenshot_url: "https://example.com/screenshot.png",
});
console.log("Download:", url);| Status | Code | Description |
|---|---|---|
| 400 | invalid_input | Missing or malformed request body |
| 401 | unauthorized | Missing or invalid API key |
| 403 | plan_required | API access requires Scale plan |
| 404 | not_found | Render ID not found or not owned by you |
| 429 | rate_limited | Monthly render limit reached |
| 500 | render_failed | Render job failed — contact support |
Scale plan customers get dedicated support. For all other questions, reach out via email.
Contact support →