Submit video generation jobs, get HMAC-signed webhook callbacks when they complete. Fast first response up front, honest async completion underneath.
Retried with exponential backoff. Deduplicated with a 7-day window. Mid-render failover across providers. Built for bulk queues, not just one-off demos.
50 free credits on signup Β· No credit card required Β· Works with any HTTP framework
Best fit for OpenMontage, automation builders, and API buyers asking whether async jobs, retries, pricing, and image-to-video delivery are trustworthy enough for production.
Fastest proof of async job shape for technical evaluators.
Buyer-safe cost framing without per-second surprises.
Public proof for retries, overload handling, and status fallback.
Direct automation example for no-code and ops-heavy buyers.
This is the honest production story for enterprise buyers: respond fast, keep heavy rendering async, and use webhook delivery as the trust layer for long-running media jobs.
Heavy video, dubbing, and lip-sync requests should return quickly with 202 Accepted + job ID. That is the fast UX moment; the final media still completes asynchronously.
Submit jobs independently with bounded concurrency so one slow or retried render does not block the rest of a catalog, campaign, or personalization run.
Signed callbacks are the safest customer-facing story for long renders: accepted quickly, updated clearly, retried automatically if your endpoint is briefly unavailable.
Generate narration with POST /api/generate/voice, then feed that audio into compose, dubbing, or lip-sync workflows without adding a separate TTS vendor.
Customer-safe proof that narration can live in the same stack as video jobs.
curl -X POST https://api.creativeai.run/api/generate/voice \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Welcome to CreativeAI. Your launch assets are rendering now.",
"voice": "alloy",
"language": "en",
"speed": 1.0,
"webhook_url": "https://your-app.com/webhooks/voice-ready"
}'
# Returns 202 Accepted with a voice job ID
# Use the resulting audio in dubbing, compose, or lip-sync workflowsThree steps. No polling loops. Your server does zero work while the video renders.
POST to /v1/video/generations with a webhook_url. Get back 202 Accepted and a job ID instantly.
Your video renders on our infrastructure (45s-4min depending on model). Automatic failover at submission and mid-render if a provider hits capacity or errors.
We POST the result to your webhook_url with HMAC signature, output URL, and job metadata. 3 delivery attempts with exponential backoff (0s, 5s, 30s).
Add webhook_url to any video generation request. The response is immediate β processing happens in the background.
import requests
resp = requests.post(
"https://api.creativeai.run/v1/video/generations",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"model": "kling-v3",
"prompt": "Product reveal animation on white background",
"duration": "5s",
"aspect_ratio": "16:9",
"webhook_url": "https://your-app.com/webhooks/creativeai"
},
)
job = resp.json()
print(job["id"]) # "vgen_abc123"
print(job["status"]) # "pending"
# Done β no polling loop needed. Your webhook gets called.Returns 202 Accepted with a job ID. Your webhook_url receives the result when processing completes.
When your job completes (or fails), we POST a JSON payload to your endpoint with signed headers.
// What your webhook endpoint receives:
POST /webhooks/creativeai
Content-Type: application/json
X-CreativeAI-Event: video.generation.completed
X-CreativeAI-Delivery-Id: vgen_abc123
X-CreativeAI-Signature: sha256=a1b2c3d4e5f6...
{
"id": "vgen_abc123",
"object": "video.generation",
"status": "completed",
"model": "kling-v3",
"prompt": "Product reveal animation on white background",
"output_url": "https://cdn.creativeai.run/output/video-abc123.mp4",
"credits": 3,
"failover_used": false,
"completed_at": "2026-03-10T14:23:01Z"
}X-CreativeAI-EventEvent type for routing
X-CreativeAI-Delivery-IdGeneration ID for dedup
X-CreativeAI-SignatureHMAC-SHA256 for verification
Every webhook is signed with your API key using HMAC-SHA256. Verify it to confirm the request came from CreativeAI.
import crypto from 'crypto';
export function verifyCreativeAiWebhook(
rawBody: string,
signatureHeader: string,
apiKey: string
): boolean {
const expected = crypto
.createHmac('sha256', apiKey)
.update(rawBody)
.digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
// In your Express/Next.js handler:
app.post('/webhooks/creativeai', (req, res) => {
const sig = req.headers['x-creativeai-signature'];
if (!verifyCreativeAiWebhook(req.rawBody, sig, API_KEY)) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
if (event.status === 'completed') {
// Save output_url, notify user, trigger next step...
}
res.status(200).send('ok');
});Built for teams running async video generation at scale. Every edge case is handled.
Every delivery includes X-CreativeAI-Signature using your API key as the HMAC secret. Constant-time comparison examples provided for Node.js and Python.
No more "Starting..." confusion. Jobs show phase-aware labels (Queued, Preparing, Rendering, Encoding, Finishing) with estimated time remaining, elapsed timer, and last-poll confirmation. Webhook payloads include the full status chain.
3 delivery attempts with exponential backoff (0s, 5s, 30s). 10-second timeout per attempt. Your endpoint can be briefly down without losing events.
Each generation + status combination is deduplicated with a 7-day window. Safe to process without building your own dedup logic.
If a provider hits capacity or 429s during rendering, the job is automatically re-submitted to a backup provider. Your webhook fires with failover_used: true β no credit surcharge.
Temporary 5xx errors from upstream providers during polling do not kill your job. Up to 5 consecutive transient failures are tolerated with exponential backoff before giving up.
Credits deducted atomically before job submission. Refunded automatically on timeout or failure β idempotent via refunded_at tracking. You only pay for completed generations.
Background tasks use Redis-based distributed locking to prevent double-processing across workers. Scheduled health checks run every 5 minutes.
Can't receive webhooks? Poll GET /v1/video/generations/{id} instead. Status is cached in Redis for fast reads. Both patterns are first-class.
Every async job passes through multiple resilience layers before your webhook fires. Here is exactly what happens when things go wrong.
Provider returns 429 (rate limit) or 5xx during job submission
Job is automatically re-submitted to the next provider in the failover chain (e.g. Kling v3 -> Seedance -> Kling O3 Pro). You are billed at the lower model price. failover_used: true in the webhook payload.
Provider hits capacity mid-render (queue full, resource exhausted)
Async capacity failover detects the pressure pattern, verifies the fallback cost is not higher than originally charged, and re-submits to a backup provider. No duplicate charge.
Upstream 5xx errors during status polling
Up to 5 consecutive transient failures are tolerated with exponential backoff (capped at 4x the poll interval). The job stays alive and resumes polling once the provider recovers.
Your webhook endpoint is down when we try to deliver
We make 3 delivery attempts (0s, 5s, 30s). Each attempt has a 10-second timeout. If all 3 fail, the result is still available via the status API.
Job exceeds maximum wait time
Job is marked as failed, credits are refunded automatically (idempotent β safe if called multiple times), and the failure webhook fires with error context and elapsed time.
Redis is temporarily unavailable for dedup
Webhook delivery continues (fail-open). Availability is prioritized over strict at-most-once semantics. Your signature verification still protects against replays.
Can't receive inbound webhooks? Poll the status endpoint instead. Both patterns are first-class.
# Optional: poll if you can't receive webhooks
import time, requests
BASE = "https://api.creativeai.run/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
# Submit without webhook_url
resp = requests.post(f"{BASE}/video/generations", headers=HEADERS, json={
"model": "kling-v3",
"prompt": "Product reveal animation",
"duration": "5s",
})
job_id = resp.json()["id"]
# Poll until complete
while True:
status = requests.get(
f"{BASE}/video/generations/{job_id}", headers=HEADERS
).json()
if status["status"] in ("completed", "failed"):
break
time.sleep(10)
print(status["output_url"]) # Video is readyRecommendation: Use webhooks for production workloads. Polling is best for quick prototyping, local development, or environments that can't receive inbound HTTP.
Async jobs + webhooks unlock production patterns that polling can't support.
Submit listing photos with a walkthrough prompt and webhook_url. When the video renders, the callback routes it to the correct MLS upload, property page, or social ad β per-listing traceability included.
Upload a product photo, get a marketing video via webhook. Feed it straight into your CMS or CDN.
Trigger video generation from a workflow, receive the result via webhook node. No custom polling logic.
Let your users generate videos. Submit jobs on their behalf, deliver results when the webhook fires.
Submit jobs independently with bounded concurrency and a webhook_url. Process completions as they arrive β no all-or-nothing batch wait.
Copy-paste webhook integration guides tailored to specific industries.
CSV manifest, bounded-concurrency submitter, signed webhook handler, per-listing JSONL tracking, and agent-friendly status copy β built for property platforms, listing-video SaaS, and media teams.
View PlaybookBatch product-image-to-video with webhook delivery, SKU-level JSONL manifests, render-status copy for Shopify PDP workflows, and bounded async concurrency patterns.
View PlaybookSign up, get an API key, submit your first video job with a webhook_url.
50 free credits. No credit card. Results in minutes.