Developers · REST APIBeta

Ship videos from code.

Everything the dashboard does — script, voiceover, visuals, captions, final render — behind one REST call. Prefer chatting? Connect Claude instead.

The API is in beta — it's stable enough to build on, but we're still polishing and responses may gain fields. Hit a rough edge? Tell us at hello@facelessgenie.ai.

Same credits as the dashboardFailed renders auto-refundKeys hashed & revocable
faceless — zsh
$ curl -X POST /api/v1/videos \ -d '{"topic": "5 facts about the deep ocean", …}'
202 Accepted { "id": "9f2c…", "creditsCost": 486 }
$ curl /api/v1/videos/9f2c…
{ "status": "PROCESSING", "progress": { "percent": 62 } }
$ curl /api/v1/videos/9f2c…
{ "status": "COMPLETED", "videoUrl": "…/video.mp4" }
finished video, ~8 min after one request
01

Quickstart

Three requests from zero to a finished mp4. Renders take 5–20 minutes and run entirely on our side.

  1. 1
    Create an API key in Settings → API

    Send it on every request: Authorization: Bearer fg_...

  2. 2
    Create a video
    curl -X POST https://www.facelessgenie.ai/api/v1/videos \
      -H "Authorization: Bearer fg_YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "topic": "5 facts about the deep ocean that sound fake",
        "formatId": "ai-images-short",
        "duration": 60
      }'

    202 → you get an id and the exact creditsCost.

  3. 3
    Poll until it's COMPLETED
    curl https://www.facelessgenie.ai/api/v1/videos/VIDEO_ID \
      -H "Authorization: Bearer fg_YOUR_API_KEY"

    Check every 30–60s. When status is COMPLETED, videoUrl is your finished mp4. Failures refund automatically.

02

Authentication

Bearer keys, created in Settings → API. Keys are shown once, stored hashed, and revocable anytime.

curl https://www.facelessgenie.ai/api/v1/account \
  -H "Authorization: Bearer fg_YOUR_API_KEY"

Every endpoint requires the header. Errors always use the same envelope: { "error": { "code", "message" } }.

03

Endpoints

Base URL https://www.facelessgenie.ai/api/v1. JSON in, JSON out. Copy-paste any example — swap in your key and go.

Building with an AI agent? This whole reference is available as plain Markdown at /developers.md — paste it into any assistant.

A tip before you start: every format ships with tuned defaults — the same models, voice, and settings the app uses. Send just topic and formatIdand you'll get our best output. Only override models or voices when you want something specific.

Catalog

Everything is self-describing — start here to see what you can make and what it costs.

GET/formats

List formats

Every video format you can create. Each entry carries its aspect ratio, duration options (in durationUnit), the extra inputs it accepts (pass values via formatInputs), and — for character formats — castSlots plus the characters/voices to fill them with.

Request
curl https://www.facelessgenie.ai/api/v1/formats \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "formats": [
    {
      "id": "ai-images-short",
      "name": "AI Images Short",
      "description": "Vertical short with AI still imagery",
      "category": "narrative",
      "aspectRatio": "9:16",
      "durationUnit": "sec",
      "durationOptions": [30, 60, 90],
      "defaultDuration": 60,
      "defaultVoiceMode": "narrator",
      "requiresCharacterReference": false,
      "modelOptions": {
        "image": [
          { "tier": "budget", "id": "p-image", "name": "P-Image", "credits": 1, "premium": false },
          { "tier": "high", "id": "nano-banana-pro", "name": "Nano Banana Pro", "credits": 8, "premium": true }
        ],
        "video": []
      },
      "inputs": [
        {
          "id": "genre",
          "label": "Genre",
          "kind": "multi-select",
          "required": false,
          "options": [{ "id": "horror", "label": "Horror" }, "…"]
        }
      ]
    },
    {
      "id": "char-duo-explainer-vlog",
      "name": "Character Duo Explainer",
      "aspectRatio": "9:16",
      "castSlots": [
        { "id": "host", "label": "Host", "required": true, "…": "…" }
      ],
      "castOptions": {
        "characters": [{ "id": "documentary-narrator", "label": "Documentary Narrator", "tier": "free" }],
        "voices": [{ "id": "voice-narrator-standard", "label": "Standard Narrator (Male)", "tier": "free" }]
      }
    }
  ]
}

Trimmed for readability — the live response includes every format and full input definitions. modelOptions lists the ONLY model ids create-video accepts for that format (same choices as the app); formats without modelOptions run a tuned pipeline with no overrides.

GET/models

List selectable models

The models a video can actually use — one image model and (for clip formats) one video model per quality tier, exactly matching the choices in the app. Pass ?formatId= for a format's exact allowed ids; these are the ONLY values create-video accepts in models.image / models.video. Script, TTS, and music models aren't selectable — every format uses its tuned defaults.

Parameters
  • formatIdstringFormat to get options for (from GET /formats). Omit for the global default tiers.
Request
curl "https://www.facelessgenie.ai/api/v1/models?formatId=ai-images-short" \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "formatId": "ai-images-short",
  "note": "This format only generates images (no video clips). Pass one of these ids in models.image, or omit for the default.",
  "modelOptions": {
    "image": [
      { "tier": "budget", "id": "p-image", "name": "P-Image", "credits": 1, "premium": false },
      { "tier": "standard", "id": "grok-imagine-image-quality", "name": "Grok Imagine Quality", "credits": 2, "premium": false },
      { "tier": "pro", "id": "gpt-image-2", "name": "OpenAI GPT Image 2", "credits": 5, "premium": true },
      { "tier": "high", "id": "nano-banana-pro", "name": "Nano Banana Pro", "credits": 8, "premium": true }
    ],
    "video": []
  }
}
GET/voices

List voices

Narrator voices grouped by provider. Use a voice's id + its provider in create-video's voiceId / voiceProvider fields.

Request
curl https://www.facelessgenie.ai/api/v1/voices \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "voices": {
    "kokoro":     [{ "id": "af_bella", "name": "Bella", "…": "…" }],
    "elevenlabs": ["… 21 voices …"],
    "fish":       ["… 35 voices …"]
  }
}
GET/account

Get account

The account your key belongs to, with the live credit balance. monthly resets with your plan; additional never expires.

Request
curl https://www.facelessgenie.ai/api/v1/account \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "email": "you@example.com",
  "name": "Your Name",
  "plan": "Creator",
  "credits": { "monthly": 1747, "additional": 200, "total": 1947 }
}

Videos

One POST runs the whole pipeline — script, voiceover, visuals, captions, final render.

POST/videos

Create a video

Creates a complete video from a topic and queues the pipeline. Returns 202 immediately — poll GET /videos/{id} until COMPLETED. Credits are charged up front; failures refund automatically.

Parameters
  • topicstringrequiredWhat the video is about (3–4000 chars).
  • formatIdstringrequiredAny id from GET /formats.
  • durationnumberIn the format's durationUnit. Defaults to the format's defaultDuration.
  • nichestringContent niche, e.g. "education". Default "general".
  • voiceId / voiceProviderstringOptional — each format picks a tuned narrator by default. Only set to use a specific voice from GET /voices (provider: kokoro | elevenlabs | fish).
  • modelsobjectAdvanced — skip this. Defaults are tuned per format and recommended. Overrides: { image?, video? } — each must be one of the format's modelOptions ids (GET /formats or GET /models?formatId=); anything else is rejected. Script/TTS/music models aren't selectable.
  • resolution"720p" | "1080p"Output resolution.
  • musicMoodstringcalm | uplifting | dramatic | mysterious | energetic | epic | lofi | cinematic | suspense | dreamy.
  • captionsobject{ enabled, position, style, mode, fontSize, color, font, case }.
  • formatInputsobjectThe format's extra inputs from GET /formats (e.g. genre, articleUrl).
  • visualStylestringcinematic | realistic | ghibli | anime | pixar | …
  • characterReferenceUrlurlReference image for character-consistent formats (upload via assets first).
  • customMusicUrlurlYour own soundtrack — must be an assetUrl from the assets endpoints.
  • watermarkTextstringCustom watermark (paid plans).
  • castobjectFor formats with castSlots: { [slotId]: { characterId, voiceId, appearance } }.
Request
curl -X POST https://www.facelessgenie.ai/api/v1/videos \
  -H "Authorization: Bearer fg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "5 facts about the deep ocean that sound fake",
    "formatId": "ai-images-short",
    "duration": 60,
    "resolution": "1080p",
    "musicMood": "mysterious"
  }'
Response
HTTP/1.1 202 Accepted

{
  "id": "fab5fce2-a770-4052-badf-b489c7153124",
  "status": "queued",
  "creditsCost": 486
}
GET/videos/{id}

Get a video / poll status

Status flows PENDING → PROCESSING → RENDERING → COMPLETED (or FAILED, which auto-refunds). Poll every 30–60 seconds; renders take 5–20 minutes. When COMPLETED, videoUrl is your finished mp4.

Request
curl https://www.facelessgenie.ai/api/v1/videos/fab5fce2-a770-4052-badf-b489c7153124 \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "id": "fab5fce2-a770-4052-badf-b489c7153124",
  "title": "5 facts about the deep ocean that sound fake",
  "status": "PROCESSING",
  "formatId": "ai-images-short",
  "videoType": "SHORT",
  "resolution": "1080p",
  "creditsCost": 486,
  "videoUrl": null,
  "thumbnailUrl": null,
  "isPublic": false,
  "progress": { "step": "images", "percent": 62, "message": "Generating scene 8/12" },
  "errorReason": null,
  "createdAt": "2026-07-09T18:37:46.999Z",
  "updatedAt": "2026-07-09T18:41:02.113Z"
}

When status is COMPLETED, videoUrl and thumbnailUrl hold permanent CDN links.

GET/videos

List videos

Your videos, newest first.

Parameters
  • limitnumber1–200, default 50.
  • videoTypestringSHORT or LONGFORM.
Request
curl "https://www.facelessgenie.ai/api/v1/videos?limit=20&videoType=SHORT" \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "videos": [
    {
      "id": "aa450193-…",
      "title": "The Beast Beneath the Moss",
      "status": "COMPLETED",
      "formatId": "character-video",
      "videoType": "SHORT",
      "videoUrl": "https://assets.facelessgenie.ai/renders/…/video.mp4",
      "thumbnailUrl": "https://assets.facelessgenie.ai/renders/…/thumb.jpg",
      "isPublic": false,
      "progress": null,
      "errorReason": null,
      "createdAt": "2026-07-01T09:12:00.000Z",
      "updatedAt": "2026-07-01T09:26:41.000Z"
    }
  ]
}
DELETE/videos/{id}

Delete a video

Permanently deletes a video and its assets. If the pipeline is still running it's cancelled and unspent credits are refunded. Cannot be undone.

Request
curl -X DELETE https://www.facelessgenie.ai/api/v1/videos/fab5fce2-… \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{ "ok": true, "refundedCredits": 486 }
POST/videos/preview-credits

Preview credit cost

Exactly what a create call will cost — same body as POST /videos (topic optional), no side effects, nothing charged.

Request
curl -X POST https://www.facelessgenie.ai/api/v1/videos/preview-credits \
  -H "Authorization: Bearer fg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "formatId": "ai-images-short", "duration": 60, "resolution": "1080p" }'
Response
{
  "formatId": "ai-images-short",
  "credits": 486,
  "estimate": false,
  "models": {
    "script": "gemini-3.5-flash",
    "tts": "kokoro",
    "image": "grok-imagine-image-quality",
    "i2v": "wan-2-5-fast",
    "music": "minimax-music-2-6"
  },
  "durationSec": 60
}

Character formats return { "estimate": true } — their final cost depends on the generated script.

Assets

Bring your own character references, music, or clips.

POST/assets/presign

Get an upload URL

Two-step upload for files up to 500 MB: presign, then PUT your bytes straight to storage with the same Content-Type. Use the returned assetUrl in create-video or register it below.

Parameters
  • fileNamestringrequiredOriginal file name (extension is kept).
  • mimeTypestringrequiredimage/*, video/* or audio/*.
  • sizeBytesnumberFile size — validated against per-type limits.
Request
curl -X POST https://www.facelessgenie.ai/api/v1/assets/presign \
  -H "Authorization: Bearer fg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "fileName": "my-character.png", "mimeType": "image/png", "sizeBytes": 204800 }'

# then upload the bytes (within 10 minutes):
curl -X PUT "UPLOAD_URL_FROM_RESPONSE" \
  -H "Content-Type: image/png" \
  --data-binary @my-character.png
Response
{
  "uploadUrl": "https://…r2.cloudflarestorage.com/…&X-Amz-Signature=…",
  "proxyUploadUrl": "https://www.facelessgenie.ai/api/v1/assets/upload/eyJ1c2VySWQiOi…",
  "assetUrl": "https://assets.facelessgenie.ai/facelessgenie-uploads/…/xK9dPq.png",
  "expiresInSec": 600
}

Sandboxed environments with egress allowlists (e.g. AI agent sandboxes) often can't reach the R2 uploadUrl host — PUT the same bytes to proxyUploadUrl instead; it's on this API's own domain and needs no extra headers. If both are blocked, the user can upload in the browser at /library?tab=uploads (assets show up in GET /assets), or allowlist www.facelessgenie.ai for the agent's network egress.

POST/assets/import

Import from a URL

Already hosted somewhere? We fetch the file server-side (direct https link, image / video / audio, up to 100 MB) and save it to your media library in one call.

Parameters
  • urlurlrequiredDirect https link to the media file.
  • namestringDisplay name — defaults to the file name.
  • kindstringcharacter | image | video | audio — defaults from the file type.
Request
curl -X POST https://www.facelessgenie.ai/api/v1/assets/import \
  -H "Authorization: Bearer fg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/track.mp3", "name": "My track" }'
Response
{
  "id": "7bd27d58-9ace-456f-ad29-412d5b4c6bcd",
  "kind": "audio",
  "name": "My track",
  "assetUrl": "https://assets.facelessgenie.ai/facelessgenie-uploads/…/xK9dPq.mp3",
  "mimeType": "audio/mpeg",
  "sizeBytes": 204800
}
POST/assets

Register an asset

Saves an uploaded file into your media library so it shows up in the dashboard and GET /assets.

Parameters
  • kindstringrequiredcharacter | image | video | audio.
  • namestringrequiredDisplay name.
  • urlurlrequiredThe assetUrl returned by presign.
  • mimeType / sizeBytes / durationSecmixedOptional metadata.
Request
curl -X POST https://www.facelessgenie.ai/api/v1/assets \
  -H "Authorization: Bearer fg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "character", "name": "My character", "url": "ASSET_URL", "mimeType": "image/png" }'
Response
{
  "id": "7bd27d58-9ace-456f-ad29-412d5b4c6bcd",
  "kind": "character",
  "name": "My character",
  "url": "https://assets.facelessgenie.ai/facelessgenie-uploads/…/xK9dPq.png",
  "createdAt": "2026-07-09T18:41:30.019Z"
}
GET/assets

List assets

Your media library — reuse any url in create-video.

Parameters
  • kindstringcharacter | image | video | audio.
  • limitnumber1–200, default 60.
Request
curl "https://www.facelessgenie.ai/api/v1/assets?kind=character&limit=20" \
  -H "Authorization: Bearer fg_YOUR_API_KEY"
Response
{
  "assets": [
    {
      "id": "7bd27d58-…",
      "kind": "character",
      "name": "My character",
      "url": "https://assets.facelessgenie.ai/…/xK9dPq.png",
      "mimeType": "image/png",
      "sizeBytes": 204800,
      "durationSec": null,
      "createdAt": "2026-07-09T18:41:30.019Z"
    }
  ]
}
04

Limits & errors

Generous for real automations, boring for abuse.

Rate limits

  • 120requests / minute
  • 10video creations / minute
  • 2videos generating at once
  • 30uploads / minute
  • 400validation_error

    The body or params are invalid — the message names the field.

  • 401unauthorized

    Missing, invalid, or revoked API key.

  • 402insufficient_credits

    Not enough credits for this video. Top up and retry.

  • 403plan_required

    No active subscription, or the plan doesn't allow this configuration.

  • 404not_found

    The resource doesn't exist or isn't yours.

  • 429rate_limited

    Slow down — respect the Retry-After header.

  • 5xxinternal_error

    Our side. Failed creations refund automatically.

05

Credits

Same pricing as the dashboard — format, duration, and model choices set the cost.

Call POST /videos/preview-credits to see the exact cost before creating, and GET /accountfor your balance. Failed renders refund automatically; deleting an in-flight video refunds what wasn't spent.

Your channel, on cron.

One API key is all it takes to wire FacelessGenie into your scripts, n8n flows, or agents.