# Aituber API

> AITuber API skill for AI video creation. Generate videos with AI narration, visuals, and captions for YouTube Shorts, TikTok, Instagram Reels, and long-form content. Supports AI-generated images, video clips, stock footage, and viral templates like skeleton and character styles. Handles the full pipeline: pick a voice, generate a video, poll for completion, export to MP4 and download, or publish to connected YouTube, TikTok, Instagram, Facebook, Threads, and X channels. TRIGGER when the user wants to: create an AI video, generate a video from a script or idea, list or browse AI voices, export a video to MP4, download a rendered video, list connected channels, publish or schedule a video to social media, check their AITuber subscription or credit balance, or automate video creation. DO NOT TRIGGER for: editing existing video files, uploading user-provided video footage, live streaming, video transcription or captioning of external files, image generation without video context, or anything unrelated to the AITu

- Skill: `aituberapp/aituber-api` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add aituberapp/aituber-api`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aituberapp/aituber-api/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: MIT
- Author: aituberapp (https://skillmd.com/u/aituberapp)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aituberapp/aituber-api

---


# AITuber API

Create AI videos from a script or idea. From 15-second Shorts to 20-minute long-form content. The API handles voice narration (1,300+ voices, any language), AI-generated visuals, word-synced captions, MP4 export, and publishing to YouTube, TikTok, Instagram, Facebook, Threads, and X.

**Base URL:** `https://app.aituber.app/api/v1`
**OpenAPI spec:** `https://app.aituber.app/api/v1/openapi.json`
**API docs:** `https://aituber.app/api`

> **Tip:** The endpoint reference and credit costs below are generated from the live API definition, so they match the current API. For interactive exploration and response schemas, use the OpenAPI spec or the docs page.

## Authentication

All endpoints except `GET /voices` require a Bearer token. Create an API key in the AITuber dashboard at https://app.aituber.app/dashboard/api-keys. Keys start with `ak_`.

```
Authorization: Bearer <AITUBER_API_KEY>
```

Store the key in the `AITUBER_API_KEY` environment variable.

## Complete Workflow

AITuber supports two common flows after generation:

- **Export flow:** pick voice, generate video, poll status, export, download
- **Publish flow:** pick voice, generate video, poll status, list channels, publish, poll publication status

### Step 1: Pick a voice

```bash
curl "https://app.aituber.app/api/v1/voices?gender=male&accent=American"
```

No auth required. Returns an array of voice objects. Use the `id` field as `voiceId` when generating, or omit `voiceId` to use the default voice.

### Step 2: Generate a video

From a script (you write the narration):

```bash
curl -X POST "https://app.aituber.app/api/v1/videos/generate" \
  -H "Authorization: Bearer $AITUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "The human brain contains roughly 86 billion neurons. Every thought, memory, and emotion is the result of electrical signals racing through this incredible network.",
    "voiceId": "VOICE_ID_FROM_STEP_1",
    "imageStyleId": "cinematic",
    "aspectRatio": "9:16"
  }'
```

From an idea (AI writes the script):

```bash
curl -X POST "https://app.aituber.app/api/v1/videos/generate" \
  -H "Authorization: Bearer $AITUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "5 mind-blowing facts about black holes",
    "inputType": "idea",
    "expectedDurationSeconds": 60
  }'
```

Returns `{ "videoId": "uuid", "status": "pending" }`.

**Video types (all use this same endpoint):**

1. **Faceless narration (images)** - Default. AI images with Ken Burns animation. Just send a script or idea.
2. **Faceless narration (video clips)** - AI video clips. Set `mediaType: "video"`.
3. **Stock footage** - Real stock footage matched to narration. Set `mediaType: "stock"`.
4. **Skeleton template** - Viral "what happens if..." X-ray style. Set `templateId: "skeleton"`. The template handles mediaType and style.
5. **Character template** - Character-driven stories. Set `templateId: "character"`, `inputType: "idea"`. Only idea mode (AI writes the script for character consistency).

For visual control in script mode, add instructions in brackets: `[A dark forest at night] The wind howled through the trees.` Each `[bracket]` tells the AI what to show for that scene.

### Step 3: Poll for completion

```bash
curl "https://app.aituber.app/api/v1/videos/VIDEO_ID" \
  -H "Authorization: Bearer $AITUBER_API_KEY"
```

Poll every 5-10 seconds. Generation typically takes 1-3 minutes. Wait until `status` is `completed` (or `failed`).

### Step 4: Export to MP4

```bash
curl -X POST "https://app.aituber.app/api/v1/exports" \
  -H "Authorization: Bearer $AITUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "videoId": "VIDEO_ID", "resolution": "1080p" }'
```

Exporting is free. Requires an active paid subscription. Poll `GET /videos/VIDEO_ID` and check `exportStatus` until it is `completed` (typically 30 seconds to 5 minutes).

### Step 5: Download the MP4

```bash
curl "https://app.aituber.app/api/v1/exports/download?videoId=VIDEO_ID" \
  -H "Authorization: Bearer $AITUBER_API_KEY"
```

Returns `{ "url": "https://...", "videoId": "..." }`. The URL is a signed temporary link that expires in 2 minutes. Download immediately.

### Step 6: Publish to connected channels

Publishing requires channels to already be connected in the AITuber dashboard and an active paid subscription with the Publish feature. If the video is not exported yet, the API starts the export automatically (no need to call `POST /exports` first).

List channels:

```bash
curl "https://app.aituber.app/api/v1/channels" \
  -H "Authorization: Bearer $AITUBER_API_KEY"
```

Publish to YouTube, TikTok, Instagram, Facebook, Threads, and X in one call:

```bash
curl -X POST "https://app.aituber.app/api/v1/publications" \
  -H "Authorization: Bearer $AITUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "videoId": "VIDEO_ID",
    "caption": "New short is live",
    "shortCaption": "New short is live. What do you think?",
    "publishNow": true,
    "channels": [
      {
        "channelId": "YOUTUBE_CHANNEL_ID",
        "title": "5 Mind-Blowing Facts",
        "tags": ["facts", "science"],
        "categoryId": "27"
      },
      {
        "channelId": "TIKTOK_CHANNEL_ID",
        "tiktokPrivacyStatus": "public",
        "isAiGenerated": true
      },
      {
        "channelId": "INSTAGRAM_CHANNEL_ID",
        "instagramPlacement": "reels"
      },
      { "channelId": "FACEBOOK_CHANNEL_ID" },
      { "channelId": "THREADS_CHANNEL_ID" },
      { "channelId": "X_CHANNEL_ID" }
    ]
  }'
```

Per-platform channel settings:
- **YouTube:** `title`, `tags`, `categoryId`, `madeForKids`
- **TikTok:** `tiktokPrivacyStatus`, `allowDuet`, `allowStitch`, `isAiGenerated`
- **Instagram:** `instagramPlacement`, `shareToFeed`
- **TikTok and X:** `allowComment`. No other platform lets us change it.

Poll publication status:

```bash
curl "https://app.aituber.app/api/v1/publications/PUBLICATION_ID" \
  -H "Authorization: Bearer $AITUBER_API_KEY"
```

Poll every 10-15 seconds until the upload reaches a stable state such as `published`, `scheduled`, or `failed`.

## Endpoints Reference

<!-- GENERATED:BEGIN endpoints -->
### GET /voices

Returns all available AI voices for video narration, sorted by popularity. **No auth required.**

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| gender | string | No | Filter by voice gender. Values: "male", "female", "neutral". |
| accent | string | No | Filter by accent (case-insensitive). Examples: "American", "British", "Australian", "Indian". |
| age | string | No | Filter by age group. Values: "young", "middle_aged", "old". |
| useCase | string | No | Filter by recommended use case (case-insensitive). Examples: "narration", "conversational", "news", "audiobook", "social_media". |
| language | string | No | Filter to voices optimized for a specific language (ISO 639-1 code). Examples: "en", "es", "fr", "hi", "zh". |
| search | string | No | Search voices by name or description (case-insensitive). Examples: "roger", "energetic", "calm". |

### GET /voices/cloned

Returns the voices you cloned in the AITuber dashboard.

### GET /avatars

Returns every avatar you can use for talking-head videos: built-in avatars available to everyone, plus your own characters.

### GET /elements

Returns your saved elements: people/characters, products/props, and places, plus the built-in ones.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| type | `character` \| `prop` \| `location` | No | Filter by element type. Omit for all. |

### POST /elements

Saves a reusable element (a person/character, product/prop, or place) with a reference photo.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| name | string | Yes | Element name, used to build the @handle. Letters, numbers, spaces, and hyphens work best (e.g. "Dhiva", "Red Bottle"). |
| type | `character` \| `prop` \| `location` | Yes | `character` = a person or mascot (also usable as an avatar), `prop` = an object or product, `location` = a place. |
| description | string | No | Optional context notes (what it is, when to use it). Do NOT describe appearance; the photo decides how the element looks. |
| imageUrl | string | No | Public URL of the reference photo (JPEG, PNG, or WebP, max 25MB). We download and store it. Use this OR imageAssetId. |
| imageAssetId | string (uuid) | No | An asset from `POST /uploads` with purpose `element-image`. Use this OR imageUrl. |

### POST /uploads

Gets a media file into your AITuber library and returns an `assetId` you can pass to other endpoints.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| purpose | `clip-reference-image` \| `clip-reference-video` \| `clip-reference-audio` \| `element-image` \| `visual-style-reference` \| `ugc-demo` \| `music` \| `voice-sample` \| `agent-attachment` | Yes | What this file is for. Only listed purposes are accepted; each unlocks specific endpoints (see the endpoint description). |
| sourceUrl | string | No | A public URL to download the file from (image purposes only). Use this OR contentType+fileSizeBytes, not both. |
| contentType | `image/jpeg` \| `image/png` \| `image/webp` \| `video/mp4` \| `video/quicktime` \| `video/webm` \| `audio/mpeg` \| `audio/wav` \| `audio/mp4` \| `audio/x-m4a` \| `audio/aac` \| `audio/mp3` \| `audio/wave` \| `audio/x-wav` \| `audio/ogg` \| `audio/webm` | No | The file type for a direct upload. Returns an `uploadUrl` to PUT the bytes to. Must match the purpose (image, video, or audio). |
| fileSizeBytes | integer | No | The file size in bytes for a direct upload. Max depends on the purpose (25MB images, 200MB video, 50MB audio). |
| durationSeconds | number | No | For video (ugc-demo, 1-180) and audio (music, 1-600) uploads: REQUIRED. The clip or track length in seconds. Used to time the segment. |
| videoWidth | integer | No | For video uploads (ugc-demo): the pixel width. Recommended so the demo is framed correctly. |
| videoHeight | integer | No | For video uploads (ugc-demo): the pixel height. Recommended so the demo is framed correctly. |

### GET /ugc/reactions

Returns short clips of a person reacting to camera, split into `system` (the built-in library) and `custom` (reactions you generated).

### POST /ugc/reactions

Generates a short clip of your character reacting to camera, using image-to-video AI.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| avatarImageUrl | string | No | Dashboard use only. Public callers pass `elementId` instead; an avatarImageUrl from the public API must be an AITuber-hosted asset URL. |
| elementId | string (uuid) | No | The character element to react. Get IDs from `GET /elements` (type `character`) or create one with `POST /elements`. |
| avatarId | string (uuid) | No | Legacy avatar ID. Prefer `elementId`. |
| reactionPrompt | string | No | Direct control over the reaction, e.g. "shocked, eyes wide, leaning back". Provide this OR hookText. |
| hookText | string | No | The hook the character is reacting to. The AI turns it into a fitting expression. Provide this OR reactionPrompt. |
| quality | `good` \| `premium` | No | Generation quality. `premium` costs more and looks better. |

### GET /ugc/reactions/{id}

Returns a reaction you generated.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string (uuid) | Yes | Reaction ID from `POST /ugc/reactions`. |

### POST /ugc/videos

Builds a finished UGC-style hook video: a person reaction clip with your hook text on top, optionally followed by your product demo video.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| hookText | string | Yes | The on-screen hook text (5-200 characters). |
| reactionId | string (uuid) | No | A reaction clip from `GET /ugc/reactions`. |
| ugcVideoId | string (uuid) | No | Dashboard alias for `reactionId`. Public callers use `reactionId`. |
| demoVideoAssetId | string (uuid) | No | Optional product demo video, uploaded via `POST /uploads` (purpose `ugc-demo`). Plays after the reaction. |
| demoVideoUrl | string | No | Dashboard use only. Public callers pass `demoVideoAssetId` instead. |
| demoDurationSeconds | number | No | Dashboard use only. Required when `demoVideoUrl` is set. |
| demoVideoWidth | integer | No | Dashboard use only. |
| demoVideoHeight | integer | No | Dashboard use only. |
| hookTextPosition | `top` \| `center` \| `bottom` | No | Where the hook text sits. |
| aspectRatio | `9:16` \| `16:9` \| `1:1` | No | Video dimensions. |
| backgroundMusicId | string (uuid) | No | Dashboard use only. Background music track ID. |
| backgroundMusicVolume | number | No | Dashboard use only. Background music volume (0-100). |
| captionStyleId | string | No | Caption style ID from `GET /caption-styles`. Default: "tiktok". |
| title | string | No | Optional video title. |

### POST /music

Generates an original song from a text prompt using AI.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| prompt | string | Yes | What the song should be about or sound like, e.g. "an upbeat indie pop track about summer road trips". In custom mode this is optional context; the words come from `lyrics` and the sound from `style`. |
| instrumental | boolean | No | Set true for a track with no vocals or lyrics. |
| customMode | boolean | No | Set true to control `style`, `title`, and `lyrics` yourself instead of letting the AI decide from `prompt`. |
| style | string | No | Custom mode only: the musical style, e.g. "lo-fi hip hop, mellow, jazzy piano". |
| title | string | No | Custom mode only: the song title. |
| lyrics | string | No | Custom mode only: the exact lyrics to sing. Ignored when `instrumental` is true. |

### GET /music

Lists tracks in your music library: songs you generated with `POST /music` and audio you uploaded with `POST /uploads` (purpose `music`).

### GET /music/{id}

Returns a song you generated.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string (uuid) | Yes | Song ID from `POST /music`. |

### POST /music-videos

Builds a music video: your song plus AI visuals, synced captions, and an optional waveform.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| musicId | string (uuid) | No | A completed song from `POST /music`. Provide this OR `musicAssetId`, not both. |
| musicAssetId | string (uuid) | No | A track uploaded with `POST /uploads` (purpose `music`). Provide this OR `musicId`, not both. |
| visualMode | `ai-images` \| `ai-video` \| `cover-image` | Yes | `ai-images` (a new AI image every few seconds), `ai-video` (short AI clips), or `cover-image` (one still for the whole song). |
| visualDirection | string | No | Optional art direction for the visuals, e.g. "neon cyberpunk city at night, moody". Mention a saved element by @handle (see `GET /elements`) to reuse it, e.g. "@Robo-Cat on a rooftop". Its photo is fed to the image model so it looks the same in every scene it appears in. Each mentioned element adds a reference charge per scene for `ai-images`. |
| imageStyleId | string | No | Image style for `ai-images`/`ai-video`. Get IDs from `GET /image-styles`. |
| imageQuality | `basic` \| `good` \| `premium` \| `max` | No | Image quality for `ai-images` (higher costs more). |
| secondsPerImage | number | No | For `ai-images`: how many seconds each image is shown. Fewer seconds means more images and more credits. |
| videoQuality | `basic` \| `good` \| `premium` \| `max` | No | Clip quality for `ai-video` (higher costs more). |
| coverImageAssetId | string (uuid) | No | For `cover-image` mode: an image uploaded with `POST /uploads` (purpose `element-image`). Required for that mode. |
| aspectRatio | `9:16` \| `16:9` \| `1:1` | No | Video dimensions. |
| captionsEnabled | boolean | No | Show word-synced lyric captions. Automatically off for instrumental tracks. |
| captionStyleId | string | No | Caption style ID from `GET /caption-styles`. |
| captionPosition | `top` \| `center` \| `bottom` | No | Where captions sit on screen. |
| showWaveform | boolean | No | Show an audio waveform animation. |
| musicTrimStartSeconds | number | No | Start the video at this point in the song (seconds). Defaults to the start. |
| musicTrimEndSeconds | number | No | End the video at this point in the song (seconds). Defaults to the full length. |

### POST /ideas

Generates a list of specific, viral-style video topic ideas for a niche or audience.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| prompt | string | Yes | The niche, audience, or theme to brainstorm for. Example: "space facts for a faceless YouTube Shorts channel". |
| language | string | No | Language for the ideas (ISO 639-1 code like "en", "es", "hi"). Default: "en". |
| count | number | No | How many ideas to generate (5-15). Default: 10. |
| source | `tool_page` \| `inline` | No | Where the request came from, for analytics only. Dashboard use; safe to omit. |
| templateId | string | No | Creation template the request came from, for analytics only. Dashboard use; safe to omit. |

### POST /scripts

Generates 2 distinct narration script variations for a topic, sized to your target duration.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| prompt | string | Yes | The topic or idea to write a script about. Example: "5 mind-blowing facts about the deep ocean". |
| duration | number | Yes | Target video duration in seconds (15-1200). The script length is sized so narration fits this duration. |
| language | string | No | Language for the script (ISO 639-1 code like "en", "es", "hi"). Default: English. |
| source | `tool_page` \| `inline` | No | Where the request came from, for analytics only. Dashboard use; safe to omit. |
| templateId | string | No | Creation template the request came from, for analytics only. Dashboard use; safe to omit. |

### GET /image-styles

Returns every image style you can use as `imageStyleId` in `POST /videos/generate` (when `mediaType` is `images`): the built-in styles, curated template styles (ids like `medical-xray`, made for `templateId: "medical"`), plus any custom styles created in the AITuber dashboard.

### GET /caption-styles

Returns every caption style you can use as `captionStyleId` in `POST /videos/generate`: the built-in styles plus any custom styles created in the AITuber dashboard.

### POST /videos/generate

Starts generating a new AI video from a script or idea.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| script | string | Yes | The content for your video. How this field is used depends on `inputType`. **Script mode** (`inputType: "script"`, default): Provide the exact narration text. This is what the voice will speak word-for-word. Must be at least 5 words. Max 30,000 characters (enough for a 20-minute video at normal voice speed). The AI automatically splits it into visual segments and generates matching visuals. **Visual control:** By default, the AI decides what visuals to show for each part of your narration. For more control, add visual instructions in brackets before each narration segment: `[A dark forest at night] The wind howled through the trees. [Glowing eyes peering from shadows] Something was watching.` Each `[bracketed text]` tells the AI exactly what to show for that scene. The text after it is the voiceover. **Put a real person, product, or place in the video (@mentions):** reference a saved element by its handle, e.g. `[@Dhiva holding @Red-Bottle] Meet the founder who started it all.` The element's reference photo is fed to the image model so the same face or product appears consistently across the whole video. Get handles from `GET /elements`; create new elements with `POST /elements`. Rules: works with `mediaType` `images` and `video`; not with `stock`. The photo decides how the element looks; never describe its appearance in the script. Mentions are spoken as the plain name (the `@` is never read aloud), and unknown handles are treated as plain words. **Idea mode** (`inputType: "idea"`): Provide a short topic or concept. The AI writes a full narration script for you. Keep it under 800 characters. Pair with `expectedDurationSeconds` to control video length. Supports any language. The voice will speak naturally in whatever language the text is written in. |
| inputType | `script` \| `idea` | No | How to interpret the `script` field. - `script` (default): Your text is the exact narration. You control every word that is spoken. - `idea`: You provide a topic and the AI writes an engaging narration script for you. Use `expectedDurationSeconds` to control the target length. |
| mediaType | `images` \| `video` \| `stock` \| `avatar` | No | The type of visuals for your video. Each produces a different look and feel. - `images` (default): AI generates a unique image for each segment, displayed with smooth Ken Burns pan/zoom animation. This is the classic "faceless narration video" style used by top YouTube channels. Most popular and cheapest option. Control the look with `imageQuality` and `imageStyleId`. - `video`: AI generates short video clips for each segment. More dynamic and cinematic than images, but costs more credits. Also used internally by the `skeleton` and `character` templates. - `stock`: Automatically finds and matches real stock footage to each segment. Great for news, educational, and documentary-style content. - `avatar`: A talking-head video where an avatar speaks your script. **Requires `avatarId` (from `GET /avatars`) and `voiceId`.** Script mode only (no idea mode), max 5 minutes, aspect ratio `9:16` or `16:9`. Costs ~480 credits per minute of video plus narration, far more than other media types. Generation also takes longer (usually 3-10 minutes). **For most use cases, leave this as default (`images`) unless you are using a template.** When using `templateId`, the template automatically selects the best media type for you, so you do not need to set `mediaType` separately. |
| avatarId | string (uuid) | No | **Required when `mediaType` is `"avatar"`.** The avatar that speaks your script. Get valid IDs from `GET /avatars` (built-in avatars plus characters created in the dashboard). Ignored for other media types. |
| motionPrompt | string | No | Optional direction for how the avatar moves and gestures, e.g. "excited, talking with hands, leaning toward the camera". Only applies when `mediaType` is `"avatar"`. |
| voiceId | string | No | The voice ID for narration. Browse all 1,300+ available voices and listen to previews at `GET /voices`, or use one of your cloned voices from `GET /voices/cloned`. If omitted, defaults to "Adam", a deep, natural American male voice. **Exception: required when `mediaType` is `"avatar"`** (no default; pick a voice that fits the avatar, or use its `defaultVoiceId` from `GET /avatars`). Filter voices by gender, accent, or use case using the `GET /voices` endpoint query parameters. Use the `previewUrl` from each voice to hear a sample before selecting. |
| voiceSpeed | number | No | Narration speed multiplier. Range: 0.7 to 1.2. - `0.7`: 30% slower. Great for educational, meditation, or non-native audiences. - `1.0` (default): Natural speed. - `1.2`: 20% faster. Great for energetic, hype, or fast-paced content. Most creators use values between 0.9 and 1.1. |
| aspectRatio | `9:16` \| `16:9` \| `1:1` | No | Video dimensions. Choose based on where you plan to publish. - `9:16` (default): Vertical/portrait. Best for YouTube Shorts, TikTok, and Instagram Reels. - `16:9`: Horizontal/landscape. Best for standard YouTube videos and presentations. - `1:1`: Square. Best for Instagram feed posts and LinkedIn. Not available for `mediaType: "avatar"`. |
| expectedDurationSeconds | number | No | Target video duration in seconds. **Required when `inputType` is `"idea"`** so the AI knows how long a script to write. Examples: `30` for a 30-second Short, `60` for a 1-minute video, `180` for a 3-minute video, `600` for a 10-minute video, `1200` for a 20-minute video. **Max varies by template:** - Default faceless template (no `templateId`): **1200 seconds (20 minutes)** - `templateId: "skeleton"` or `templateId: "character"`: **420 seconds (7 minutes)** (these templates have different cost profiles and are not designed for long-form content) Passing a value above the template-specific cap returns a 400 error. Ignored when `inputType` is `"script"` because the duration is determined by the word count. |
| imageQuality | `basic` \| `good` \| `premium` \| `max` | No | Image generation quality tier. Only applies when `mediaType` is `"images"`. Higher quality produces more detailed, accurate images but costs more credits per image. - `basic` (default): 1 credit/image. Fast generation. Good for testing and drafts. - `good`: 5 credits/image. Better detail and accuracy. Good for most published content. - `premium`: 10 credits/image. High detail, very accurate to the script. Great for professional content. - `max`: 20 credits/image. Maximum quality. Best for high-production content. A typical 60-second video has 15-18 images (one every 3-5 seconds), so factor that into credit calculations. Every tier can use the reference photo of an @mentioned saved element. Each photo used in a scene adds 3 credits to that scene, on top of the tier price above. |
| imageStyleId | string | No | Visual art style for AI-generated images. Only applies when `mediaType` is `"images"`. Each style applies a consistent aesthetic across all images in your video. **Realistic:** - `photorealistic` (default): Hyperrealistic photography, DSLR quality. - `cinematic`: 35mm film look, dramatic lighting, movie still aesthetic. - `vintage-retro`: 1980s VHS aesthetic, neon colors, synthwave vibes. - `noir`: Classic black and white film noir, dramatic shadows. **Illustrated:** - `3d-pixar`: 3D Pixar-style cartoon, smooth rounded shapes. - `anime`: Japanese anime/manga style, cel-shaded, vibrant colors. - `digital-art`: Professional concept art, Artstation quality. - `comic-book`: American comic book, bold outlines, halftone shading. **Artistic:** - `pencil-sketch`: Detailed graphite pencil drawing on textured paper. - `oil-painting`: Classical oil painting with visible brushstrokes. - `watercolor`: Soft watercolor with translucent color washes. - `pop-art`: Andy Warhol style, bold primary colors. **Modern:** - `kurzgesagt`: Flat vector educational style (like the YouTube channel). - `pixel-art`: Retro 16-bit video game aesthetic. - `minimalist`: Clean, simple, lots of white space. - `claymation`: Stop-motion clay animation, Aardman-inspired. And 11 more styles. Combine with `imageStyleCustom` for fine-tuning. |
| captionStyleId | string | No | Caption (subtitle) visual style. Captions are rendered directly onto the video with word-by-word timing sync. **Built-in styles:** - `wrap-1` (default): Active word highlight with 2-word groups. Most popular style. - `hormozi`: Bold uppercase with yellow highlight on black pill. Alex Hormozi inspired. - `beast`: Bold Bangers font with letter-spacing bounce animation. MrBeast inspired. - `noah`: Bold italic Oswald with colored highlight. - `handwritten`: Organic casual style with handwriting font. Personal and authentic. - `subtitle`: Clean streaming-style subtitles on a dark bar. Professional and readable. - `impact`: Massive bold text, one word at a time. Maximum emphasis. - `pop`: Playful spring animation with bouncy words. Fun and energetic. - `chronicle`: Ancient serif for history, mythology, and epic stories. - `cyber`: Futuristic neon style for sci-fi, tech, and cyberpunk content. - `grit`: Raw marker style for true crime, street, and intense stories. - `luxe`: Elegant serif for luxury, fashion, and celebrity content. - `terminal`: Monospace style for tech, hacker, and AI content. You can also create custom caption styles with your own fonts, colors, and animations via the [AITuber dashboard](https://app.aituber.app/dashboard). Use the custom style ID here. |
| captionsEnabled | boolean | No | Whether to show captions (subtitles) on the video. Default: `true`. Captions are auto-synced word-by-word to the narration. We strongly recommend keeping captions on as they significantly boost engagement, accessibility, and watch time. Set to `false` only for music-only or ambient videos. |
| captionPosition | string | No | Vertical position of captions on the video. - `bottom` (default): Captions at the bottom of the screen. - `center`: Captions in the middle of the screen. - `top`: Captions at the top of the screen. Not supported for `mediaType: "avatar"` (avatar captions always use the default position). |
| videoQuality | string | No | Video clip generation quality. Only applies when `mediaType` is `"video"`. - `basic`: Fastest generation, lower visual quality. - `good` (default): Good balance of quality and speed. - `premium`: High quality video clips. Slower generation. - `max`: 1080p clips, the sharpest we make. Costs the most per second. |
| templateId | string | No | Specialized video template that applies a specific visual format and style. Leave empty for standard faceless narration videos (the default). **Available templates:** - `skeleton`: "What happens if..." style educational videos with skeleton/X-ray visuals. Uses AI video generation internally. Popular viral format on YouTube Shorts. Example script: `"What happens if you eat only ice cream for 30 days"`. - `medical`: Medical animation videos with scientifically accurate anatomy, for health education, patient explainers, and clinic content. Works with `mediaType` `images` (default) or `video` only (no stock: stock libraries carry no anatomy footage). Optional curated styles via `imageStyleId`: `medical-3d` (realistic 3D), `medical-translucent` (see-through body), `medical-xray`, `medical-darkstudio` (organ on black), `medical-cartoon` (patient-friendly), or omit for auto. Example idea: `"How a total knee replacement works, step by step"`. - `character`: Character-driven animated videos. AI generates a consistent character across all scenes and animates them. Uses AI video generation internally. Example script: `"A robot learns what friendship means on its first day at school"`. **Important:** When you set a template, it handles the visual settings for you; just provide your `script` (or `inputType: "idea"` with a topic). `skeleton` and `character` also pin `mediaType` automatically. `medical` keeps `mediaType` open: send `images` (default) or `video`; sending `stock` returns a 400. For talking-head avatar videos, do NOT use a template: set `mediaType: "avatar"` with an `avatarId` instead. |

### GET /videos

Returns all videos for your organization, sorted newest first.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| limit | number | No | Maximum number of videos to return per page. Default: 50, max: 100. |
| cursor | string (uuid) | No | Pagination cursor: the `id` of the LAST video from the previous page. Returns videos older than that one. Omit for the first page. An empty array means there are no more videos. |

### GET /videos/{id}

Returns details for a single video.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string (uuid) | Yes | The video ID returned from `POST /generate` or `GET /videos`. |

### DELETE /videos/{id}

Permanently deletes a video and its generated assets.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string (uuid) | Yes | The video ID to delete. |

### GET /clip-models

Returns the AI video models available for standalone clip generation, with their capabilities (text-to-video, image-to-video, reference images), supported aspect ratios, resolutions, duration limits, and credit cost per second by resolution.

### POST /clips

Starts generating a single AI video clip (1-30 seconds) from a text prompt, an image, or both.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | No | Optional clip title. Defaults to the start of the prompt. |
| modelKey | string | Yes | The generation model to use. Get valid keys, capabilities, and per-second costs from `GET /clip-models`. |
| prompt | string | No | What the clip should show. Required for text-to-video models; optional when animating from images. |
| aspectRatio | `auto` \| `16:9` \| `9:16` \| `4:3` \| `3:4` \| `1:1` \| `21:9` \| `3:2` \| `2:3` \| `9:21` \| `5:4` \| `4:5` | No | Clip dimensions. Check the model's `supportedAspectRatios` from `GET /clip-models`. Default: "16:9". |
| resolution | string | No | Output resolution (e.g. "720p", "1080p"). Check the model's `supportedResolutions`. Higher resolutions cost more credits per second. Default: "720p". |
| durationSeconds | integer \| `auto` | No | Clip length in seconds, or "auto" for models that support automatic duration. Default: 5. |
| firstFrameUrl | string | No | Public image URL to use as the first frame (image-to-video). Only for models with `supportsFirstFrame`. |
| lastFrameUrl | string | No | Public image URL to use as the last frame. Only for models with `supportsLastFrame`. |
| referenceImageUrls | array of string | No | Public image URLs used as style/subject references. Only for models with `supportsReferenceImages`; respect `maxReferenceImages`. |
| referenceVideoUrls | array of string | No | Public video URLs used for motion, editing, or extension. Check model capabilities first. |
| referenceAudioUrls | array of string | No | Public audio URLs used for voice, lip sync, rhythm, or timing. Check model capabilities first. |

### GET /clips

Returns your standalone AI clips, newest first.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| limit | integer | No | Maximum clips per page (1-50). Default: 20. |
| cursor | datetime (ISO 8601) | No | Pagination cursor: the `createdAt` of the last clip from the previous page. Omit for the first page. |

### GET /clips/{id}

Returns a clip with its generation status.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| id | string (uuid) | Yes | Clip ID from `POST /clips`. |

### POST /exports

Starts rendering a completed video into a downloadable MP4 file.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| videoId | string (uuid) | Yes | The ID of the video to export. The video must have `status: completed`. |
| resolution | `1080p` \| `4k` | No | Export resolution. - `1080p` (default): Full HD (1920x1080 or 1080x1920 for vertical). Fast rendering. - `4k`: Ultra HD (3840x2160 or 2160x3840 for vertical). Slower rendering, larger file. |

### GET /exports/download

Returns a temporary signed URL to download the rendered MP4 file for a video.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| videoId | string (uuid) | No | The video ID. Finds the latest completed export for this video. |
| exportId | string (uuid) | No | A specific export ID, returned from `POST /exports`. Usually not needed since `videoId` automatically finds the latest export. |

### GET /channels

Returns all connected social media channels (YouTube, TikTok, Instagram, Facebook, Threads, and X) for your organization.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| platform | `youtube` \| `tiktok` \| `instagram` \| `facebook` \| `threads` \| `x` \| `all` | No | Filter by platform. Use "all" or omit to list all connected channels. |

### POST /publications

Publishes a completed video to one or more connected social media channels (YouTube, TikTok, Instagram, Facebook, Threads, and X).

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| videoId | string (uuid) | Yes | The video to publish. Must have `status: completed`. |
| sceneExportId | string (uuid) | No | Optional export ID if the video has already been exported. If omitted, an export is triggered automatically. |
| caption | string | No | Description or long caption used for YouTube, TikTok, Instagram, and Facebook. Max 2200 characters. |
| shortCaption | string | No | Short caption shared by X and Threads. It is kept within X's standard weighted 280-character limit. Defaults to `caption` when omitted. |
| addMadeWithCaption | boolean | No | Add "Made with AITuber, the AI video generator: aituber.app" at the end of each caption. Default: true. Each caption is shortened when needed to stay within its platform limit. |
| publishNow | boolean | No | Set to `true` (default) to publish immediately. Set to `false` and provide `scheduledAt` to schedule. |
| scheduledAt | datetime (ISO 8601) | No | ISO 8601 datetime to schedule publication. Must be in the future. Only used when `publishNow` is `false`. |
| channels | array of objects | Yes | One or more channels to publish to. Each entry can include platform-specific settings. |
| channels[].channelId | string (uuid) | Yes | Channel ID from `GET /channels`. Must have `status: connected`. |
| channels[].title | string | No | Video title (YouTube). Max 100 characters. Defaults to the video title from generation. |
| channels[].tags | array of string | No | YouTube tags for search discovery. Max 30 tags, each up to 100 characters. |
| channels[].categoryId | string | No | YouTube category ID. Default: "22" (People & Blogs). Common: "24" Entertainment, "27" Education, "26" Howto & Style, "28" Science & Technology, "20" Gaming, "10" Music, "17" Sports, "1" Film & Animation, "23" Comedy. |
| channels[].madeForKids | boolean | No | YouTube COPPA compliance flag. Default: false. |
| channels[].allowComment | boolean | No | Let viewers comment. Default: true. Only TikTok and X support this. TikTok turns comments off. X has no full off switch, so it limits replies to accounts you mention. Ignored on YouTube, Instagram, Facebook, and Threads. |
| channels[].tiktokPrivacyStatus | `public` \| `friends` \| `private` | No | Privacy setting. Default: "public". |
| channels[].allowDuet | boolean | No | Allow duets. Default: true. |
| channels[].allowStitch | boolean | No | Allow stitches. Default: true. |
| channels[].isAiGenerated | boolean | No | Label video as AI-generated on TikTok. Default: false. |
| channels[].instagramPlacement | `reels` \| `stories` \| `timeline` | No | Instagram: where to post. Default: "reels". |
| channels[].shareToFeed | boolean | No | Instagram: also share Reel to feed. Default: true. |

### GET /publications/{publicationId}

Returns the current status of a publication.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| publicationId | string (uuid) | Yes | Publication ID from `POST /publications`. |

### DELETE /publications/{publicationId}

Cancels a future scheduled publication before it goes live.

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| publicationId | string (uuid) | Yes | Publication ID to cancel. |

### GET /subscription

Returns your current plan and credit balance.
<!-- GENERATED:END endpoints -->

## Credit Costs

<!-- GENERATED:BEGIN credits -->
| Operation | Cost |
|-----------|------|
| Image (basic) | 1 credit/image |
| Image (good) | 5 credits/image |
| Image (premium) | 10 credits/image |
| Image (max) | 20 credits/image |
| Each reference photo in a scene | +3 credits |
| Audio narration | ~30 credits/minute |
| AI video clips (basic) | 5 credits/second (~25 per 5s clip) |
| AI video clips (good) | 10 credits/second (~50 per 5s clip) |
| AI video clips (premium) | 26 credits/second (~130 per 5s clip) |
| AI video clips 

…(truncated)
