Skip to content

API Documentation

Everything you need to integrate UltimateCreator.ai into your applications.

Getting Started

The UltimateCreator AI API lets you generate cinematic avatar videos, manage digital twins, and distribute content programmatically. All requests use the following base URL:

https://api.ultimatecreator.ai/v1

Quick Start

Include your API key in the Authorization header as a Bearer token. Here's a quick example:

bash
curl -X POST https://api.ultimatecreator.ai/v1/video/generate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-123" \
  -d '{
    "prompt": "A tech CEO delivering a keynote on stage",
    "duration_seconds": 30,
    "avatar_id": "avt_abc123"
  }'

Authentication

API keys are managed in the Portal dashboard. Each key is scoped to a project and can be rotated at any time without downtime.

Header
Authorization: Bearer <YOUR_API_KEY>
Content Type
Content-Type: application/json

Security Best Practice

Never expose your API key in client-side code. Always make API calls from your server. Use environment variables to store keys and rotate them regularly.

Video Generation

Async Processing — Do NOT Hold Connections Open

AI video generation takes 2–8 minutes depending on duration and complexity. Submit a job and either poll for status or configure a webhook. Do NOT hold HTTP connections open waiting for completion — your request will time out.

Create a Video Job

POST/v1/video/generate

Submits an asynchronous video generation job. Returns immediately with a job ID you can use to track progress.

Request Body

json
{
  "prompt": "A tech CEO delivering a keynote on stage",
  "duration_seconds": 30,
  "avatar_id": "avt_abc123",
  "brand_kit_id": "bk_xyz789",
  "resolution": "1080p",
  "webhook_url": "https://your-server.com/webhooks/video"
}

Response — 202 Accepted

json
{
  "job_id": "job_01HXYZ",
  "status": "queued",
  "credits_charged": 150,
  "estimated_duration_seconds": 240,
  "created_at": "2025-03-06T12:00:00Z"
}

Idempotency-Key Header

Include an Idempotency-Key header with a unique UUID on every POST request. If a network error occurs and you retry, the API will return the original response instead of creating a duplicate job. Keys expire after 24 hours.

Poll Job Status

GET/v1/video/{job_id}/status

Returns the current status and progress of a video generation job. Poll every 10–30 seconds until status is completed or failed.

json
{
  "job_id": "job_01HXYZ",
  "status": "completed",
  "progress_percent": 100,
  "video_url": "https://cdn.ultimatecreator.ai/v/job_01HXYZ.mp4",
  "thumbnail_url": "https://cdn.ultimatecreator.ai/t/job_01HXYZ.jpg",
  "duration_seconds": 30,
  "credits_charged": 150,
  "created_at": "2025-03-06T12:00:00Z",
  "completed_at": "2025-03-06T12:04:12Z"
}

Status Values

queuedJob received, waiting for processing
processingVideo is being generated
completedVideo is ready for download
failedGeneration failed — check error_message
cancelledJob was cancelled by the user

Cancel a Job

POST/v1/video/{job_id}/cancel

Cancels a queued or in-progress job. Credits for unprocessed seconds are refunded automatically.

Webhooks

Configure webhook endpoints to receive real-time notifications when jobs complete, fail, or require action. This is the recommended approach instead of polling.

Configuration

Set your webhook URL in the Portal dashboard under Settings → Webhooks, or include a webhook_url field in your video generation request for per-job callbacks.

Payload Format

json
{
  "event": "video.job.completed",
  "timestamp": "2025-03-06T12:04:12Z",
  "data": {
    "job_id": "job_01HXYZ",
    "status": "completed",
    "video_url": "https://cdn.ultimatecreator.ai/v/job_01HXYZ.mp4",
    "thumbnail_url": "https://cdn.ultimatecreator.ai/t/job_01HXYZ.jpg",
    "duration_seconds": 30,
    "credits_charged": 150
  }
}

Event Types

  • video.job.completedVideo generation finished successfully
  • video.job.failedVideo generation encountered an error
  • video.job.progressProgress update (every 25%)

Signature Verification

Every webhook request includes an X-UC-Signature header containing an HMAC-SHA256 hex digest of the request body, signed with your webhook secret. Always verify this signature before processing.

Node.js

javascript
import crypto from "crypto";

function verifyWebhookSignature(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body, "utf8")
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex")
  );
}

// Express middleware example
app.post("/webhooks/video", (req, res) => {
  const signature = req.headers["x-uc-signature"];
  const isValid = verifyWebhookSignature(
    req.rawBody, signature, process.env.WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const event = req.body;
  console.log("Received:", event.event, event.data.job_id);
  res.status(200).json({ received: true });
});

Python

python
import hmac
import hashlib

def verify_webhook_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route("/webhooks/video", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-UC-Signature", "")
    if not verify_webhook_signature(
        request.get_data(), signature, os.environ["WEBHOOK_SECRET"]
    ):
        return {"error": "Invalid signature"}, 401

    event = request.get_json()
    print(f"Received: {event['event']} for {event['data']['job_id']}")
    return {"received": True}, 200

Retry Policy & Dead Letter Queue

Failed webhook deliveries (non-2xx response or timeout after 10s) are retried with exponential backoff:

1st retry30 seconds
2nd retry5 minutes
3rd retry30 minutes

After 3 failed attempts, the event is moved to a Dead Letter Queue (DLQ) visible in the Portal dashboard. You can inspect the payload and manually replay any event.

Avatars

Manage your digital twin avatars with full CRUD operations.

MethodEndpointDescription
GET/v1/avatarsList all avatars
POST/v1/avatarsCreate a new avatar
GET/v1/avatars/{id}Get avatar details
PATCH/v1/avatars/{id}Update an avatar
DELETE/v1/avatars/{id}Delete an avatar

Code Examples

Complete end-to-end examples showing how to submit a video generation job, poll for status, and handle webhook callbacks.

Node.js (fetch)

javascript
const API_BASE = "https://api.ultimatecreator.ai/v1";
const API_KEY = process.env.UC_API_KEY;

async function generateVideo() {
  // 1. Submit the job
  const createRes = await fetch(`${API_BASE}/video/generate`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      prompt: "A tech CEO delivering a keynote on stage",
      duration_seconds: 30,
      avatar_id: "avt_abc123",
      resolution: "1080p",
    }),
  });

  if (!createRes.ok) {
    const err = await createRes.json();
    throw new Error(`Job creation failed: ${err.message}`);
  }

  const { job_id } = await createRes.json();
  console.log("Job created:", job_id);

  // 2. Poll for status
  let status = "queued";
  while (status !== "completed" && status !== "failed") {
    await new Promise((r) => setTimeout(r, 15_000)); // wait 15s

    const statusRes = await fetch(
      `${API_BASE}/video/${job_id}/status`,
      { headers: { "Authorization": `Bearer ${API_KEY}` } }
    );

    const job = await statusRes.json();
    status = job.status;
    console.log(`Status: ${status} (${job.progress_percent ?? 0}%)`);
  }

  if (status === "failed") {
    throw new Error("Video generation failed");
  }

  // 3. Get the final result
  const resultRes = await fetch(
    `${API_BASE}/video/${job_id}/status`,
    { headers: { "Authorization": `Bearer ${API_KEY}` } }
  );
  const result = await resultRes.json();
  console.log("Video URL:", result.video_url);
  return result;
}

generateVideo().catch(console.error);

Python (requests)

python
import os
import time
import uuid
import requests

API_BASE = "https://api.ultimatecreator.ai/v1"
API_KEY = os.environ["UC_API_KEY"]

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def generate_video():
    # 1. Submit the job
    create_res = requests.post(
        f"{API_BASE}/video/generate",
        headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
        json={
            "prompt": "A tech CEO delivering a keynote on stage",
            "duration_seconds": 30,
            "avatar_id": "avt_abc123",
            "resolution": "1080p",
        },
    )
    create_res.raise_for_status()
    job_id = create_res.json()["job_id"]
    print(f"Job created: {job_id}")

    # 2. Poll for status
    status = "queued"
    while status not in ("completed", "failed"):
        time.sleep(15)

        status_res = requests.get(
            f"{API_BASE}/video/{job_id}/status",
            headers=headers,
        )
        status_res.raise_for_status()
        job = status_res.json()
        status = job["status"]
        print(f"Status: {status} ({job.get('progress_percent', 0)}%)")

    if status == "failed":
        raise RuntimeError("Video generation failed")

    # 3. Get the final result
    result = requests.get(
        f"{API_BASE}/video/{job_id}/status", headers=headers
    ).json()
    print(f"Video URL: {result['video_url']}")
    return result


if __name__ == "__main__":
    generate_video()

Rate Limits

API requests are rate-limited based on your plan tier. When you exceed the limit, requests return 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.

PlanRequests / MinuteConcurrent Jobs
Developer602
Creator Pro1205
Agency Studio30015
EnterpriseCustomCustom

Rate Limit Headers

X-RateLimit-Limit — Maximum requests per window

X-RateLimit-Remaining — Requests remaining in current window

X-RateLimit-Reset — Unix timestamp when the window resets

Error Codes

All error responses follow a consistent format with a machine-readable error code and human-readable message.

json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry after 30 seconds.",
    "status": 429,
    "retry_after": 30
  }
}
CodeMeaningDescription
400Bad RequestPrompt blocked by moderation filter or malformed request body.
401UnauthorizedMissing or invalid API key.
403ForbiddenIP not whitelisted or API key lacks required scope.
404Not FoundThe requested resource does not exist.
422Unprocessable EntityRequest body validation failed. Check the error details.
429Too Many RequestsRate limit exceeded. Retry after the Retry-After header value.
500Internal Server ErrorSomething went wrong on our side. Please retry or contact support.