API documentation
Everything you do on the aigens website can be done from a script: write a script from an idea, create episodes, generate character images, render, download videos, and make trending videos. Limits are the same as on the website; a few actions are priced differently, see Pricing for API calls.
Contents
1. Base URL and keys
Base URL: https://aigens.app. Create a key on the API page in the studio, then send it with every request in the Authorization header:
curl https://aigens.app/api/me \ -H "Authorization: Bearer aig_YOUR_KEY"
- A key is shown only once, when it is created. If you lose it, revoke it and create a new one; each account can have up to 5 keys.
- A key can do everything the account can, including spending spirit stones. Never put a key in code that runs in a browser or in a public repository.
- Keys cannot be used to create or revoke keys, or for admin endpoints.
2. General conventions
- Requests and responses are JSON (except file uploads, which use multipart forms).
- Errors return an HTTP status of 400 or above with
{ "error": "human-readable message", "code": "CODE" }. The message follows your Accept-Language header (Vietnamese by default). Thecodefield is present when the error is one of the predefined kinds. - Common statuses: 401 wrong or revoked key; 402 not enough spirit stones; 409 the action can't be done right now (a scene is rendering, a character has no image:
CAST_NOT_READY); 422 the script doesn't match the format, with a list ofissuesper scene. - Rate limits per account: reads (GET) 120 per minute, writes (POST, PATCH, DELETE) 20 per minute. Going over returns 429 with
"code": "RATE_LIMITED"and aRetry-Afterheader (seconds to wait). Sending a wrong key many times in a row blocks you for one minute. - Three actions spend spirit stones: writing a script from an idea, sending scenes to render, and sending a trending video. Failed runs are refunded automatically.
- Rendering runs in the background. Polling the status every 5 to 15 seconds is enough.
3. Pricing for API calls
When you call with an API key, content-generating actions have their own prices: rendering scenes and trending videos cost the website price times 150%, rounded up. First-time offers (your first video, your first trending run) are only available on the website; API calls don't get the discount and don't use it up either.
| Action | On the website | Via the API |
|---|---|---|
| Write a script from an idea (each time) | free | 2 spirit stones |
| Render one scene (including redos) | 5 spirit stones | 8 spirit stones |
| One trending video | 20 spirit stones | 30 spirit stones |
| Create episodes, character images, stitching, reading data | free | free |
Current prices are always in GET /api/me, under pricing.api. The quote in GET /api/episodes/{id} already uses API prices when you call with a key. Every charge returns charged; the spirit stone ledger adds "(API)". A failed script draft is refunded right away.
4. Making an episode, step by step
The six steps below match the steps you click through on the website. A complete, runnable version is in the Python example at the top of this page.
Step 1. The system writes a script from your idea (free)
curl -X POST https://aigens.app/api/episodes/draft \
-H "Authorization: Bearer $AIGENS_KEY" -H "Content-Type: application/json" \
-d '{"idea": "The Tortoise and the Hare race a second time, with a surprise ending.", "sceneCount": 5, "voiceGender": "female"}'
# Returns: { "json": "<JSON prompt string>", "issues": [] }A JSON prompt has the shape { title, style, characters: [{ key, name, description }], scenes: [{ prompt, voice }] }. You can edit it before creating the episode, or write the whole JSON yourself and skip this step. Whenever a character appears in a scene, that scene's prompt must mention the character's exact key.
Step 2. Create the episode (free)
curl -X POST https://aigens.app/api/episodes \
-H "Authorization: Bearer $AIGENS_KEY" -H "Content-Type: application/json" \
-d '{"json": "<JSON prompt string from step 1>", "aspect": "9:16", "voiceGender": "female", "captions": true}'
# Returns: { "id": "<episode id>" }Step 3. Character images (free)
Read the episode to get its characters, request an image for each one, wait until the status becomes pending_review, then approve it. If you have your own image, upload it instead of generating one; uploaded images are approved right away.
curl https://aigens.app/api/episodes/$EPISODE -H "Authorization: Bearer $AIGENS_KEY"
# episode.cast: [{ "id": "...", "key": "character_tho", "status": "no_image" }, ...]
curl -X POST https://aigens.app/api/characters/episode/$CHARACTER/image -H "Authorization: Bearer $AIGENS_KEY"
curl -X POST https://aigens.app/api/characters/episode/$CHARACTER/approve -H "Authorization: Bearer $AIGENS_KEY"
# Or use your own image:
curl -X POST https://aigens.app/api/characters/episode/$CHARACTER/upload \
-H "Authorization: Bearer $AIGENS_KEY" -F "image=@hare.jpg;type=image/jpeg"Step 4. Render (spends spirit stones)
curl -X POST https://aigens.app/api/episodes/$EPISODE/render \
-H "Authorization: Bearer $AIGENS_KEY" -H "Content-Type: application/json" -d '{}'
# Returns: { "charged": 50, "scenes": 5, "balance": 450 }The amount to be charged is in quote.total when you read the episode. To redo a few scenes, send {"sceneIds": ["<scene id>"]}.
Step 5. Wait for rendering and stitching
Read the episode again until episode.status is done. In automatic stitch mode, the system stitches as soon as the last scene is finished.
| waiting_cast | Some characters don't have an approved image yet |
| validated | Ready to render |
| rendering | Rendering scenes. If no rendering accounts are available, the episode stays in this state until one frees up, without an error |
| stitching | All scenes are done; stitching |
| done | The full episode video is ready |
| partial | Some scenes failed. Failed scenes were refunded; resend them with sceneIds |
Step 6. Download the video
curl -L -o episode.mp4 https://aigens.app/api/episodes/$EPISODE/download -H "Authorization: Bearer $AIGENS_KEY"
Videos are kept for a limited time (see keepDays in /api/me). After that the video is deleted; the script and characters stay.
5. Trending videos
Send a character image together with a source video (a file, or a TikTok link). The system replaces the main character of the video with the character in the image and keeps the original audio.
curl -X POST https://aigens.app/api/trends \
-H "Authorization: Bearer $AIGENS_KEY" \
-F "character=@character.jpg;type=image/jpeg" \
-F "video=@source.mp4;type=video/mp4"
# or replace the video line with: -F "url=https://www.tiktok.com/@.../video/..."
# Returns: { "id": "<video id>", "cost": 30 }
curl https://aigens.app/api/trends -H "Authorization: Bearer $AIGENS_KEY"
# trends: [{ "id": "...", "status": "queued | processing | done | failed | expired", "error": null }], terms: { "cost": 30, "maxSeconds": 30 }
curl -L -o result.mp4 "https://aigens.app/api/trends/$VIDEO/video?download=1" -H "Authorization: Bearer $AIGENS_KEY"You must state the file type in the form (type=image/jpeg, type=video/mp4); the server checks it. The price and the number of seconds used are in terms.
6. Common endpoints
| GET | /api/me | Account, spirit stone balance, current prices and limits |
| GET | /api/voices | Reader voices you can pick for an episode in one video language (language, e.g. ?language=en-US; vi-VN by default): id, name, gender, language, style, sampleUrl (sample clip link, may be null); plus languages: every video language that has voices |
| POST | /api/episodes/draft | The system writes a script (JSON prompt) from an idea: idea (up to 2,000 characters), sceneCount, language (the video language: the title, character names and voiceover are written in it; defaults to the voice's language, then vi-VN), voiceId or voiceGender, projectId. SPENDS SPIRIT STONES when called with an API key (refunded if no script could be written); returns charged |
| POST | /api/episodes | Create an episode from a JSON prompt: json, idea, aspect (9:16 or 16:9), language (the video language, must match the voice's language; defaults to the voice's language, then vi-VN), voiceId (the id of a voice from GET /api/voices) or voiceGender (male by default, or female: the first voice of that gender in the video language), speed (1, 1.1 by default, 1.2, 1.25, 1.5), outputResolution (720p by default, or 1080p: the final video's resolution; stitching 1080p takes longer), captions, stitchMode (auto or review), projectId, autoCharacterImages (true by default: queue image generation for characters without an image; false if you upload your own). Free |
| GET | /api/episodes | List episodes: limit, offset, projectId or loose=1 |
| GET | /api/episodes/{id} | One episode: status, characters, each scene, plus a price quote (quote) |
| PATCH | /api/episodes/{id} | Change the title, style, aspect ratio, captions, stitch mode, speed (speed), final video resolution (outputResolution), reader voice (voiceId or voiceGender, in the episode's video language; locked once a scene has been sent to render) |
| DELETE | /api/episodes/{id} | Delete the episode |
| POST | /api/characters/episode/{id}/image | Request an image for one of the episode's characters. Free, with a daily regeneration quota |
| POST | /api/characters/episode/{id}/upload | Upload your own image for a character: multipart form, field image. Approved right away |
| POST | /api/characters/episode/{id}/approve | Approve a character image |
| PATCH | /api/scenes/{id} | Edit the image prompt or voiceover of a scene that hasn't been sent to render |
| POST | /api/episodes/{id}/render | Render and SPEND SPIRIT STONES. No body: every draft scene. sceneIds: redo those scenes |
| POST | /api/episodes/{id}/stitch | Stitch, or re-stitch, into one video. Free |
| GET | /api/scenes/{id}/video | Redirects to a scene's video; add ?download=1 to download it |
| GET | /api/episodes/{id}/download | Redirects to the download link of the full episode video |
| GET | /api/trends | Your trending videos, your balance, and terms: the next run's price and the number of seconds used |
| POST | /api/trends | Send a trending video and SPEND SPIRIT STONES: multipart form, kind (video type, swap_character by default: replace the character), character (image) plus video (file) or url (TikTok link) |
| GET | /api/trends/{id}/video | Redirects to the result video; add ?download=1 to download it |
| GET | /api/wallet | Balance and spirit stone ledger |
7. Limits
Rate limits apply only to calls with an API key and are counted per minute for each account (all keys of an account share them):
- Reads (GET): 120 per minute.
- Writes (POST, PATCH, DELETE): 20 per minute.
- Sending a wrong key 20 times within a minute from the same IP address blocks every key from that IP until the minute is over.
- Over the limit: HTTP 429,
{ "code": "RATE_LIMITED", "retryAfter": 37 }, with the headersRetry-After,X-RateLimit-Limit,X-RateLimit-Remaining.
Content limits currently in effect (the same as on the website; the latest numbers are always in GET /api/me, under limits):
| Scenes per episode | up to 10 |
| Length of each scene | 10 to 10 seconds |
| Voiceover per scene | 15 to 45 words |
| Image prompt per scene | up to 2000 characters |
| Prompt sent per scene | up to 4000 characters, including the style and the descriptions of the characters in the scene |
| Characters | up to 20 per episode, 5 per scene |
| Regenerating character images | 300 times a day for the whole account (the first image of a character doesn't count) |
| Uploaded character images | up to 8 MB |
| Trending videos | uses the first 30 seconds; source videos up to 60 seconds and 80 MB; character images up to 8 MB |
| Video retention | stitched videos are kept 3 days; scenes of an unstitched episode are kept 7 days |
8. Error codes
Every error returns JSON { "error": "human-readable message", "code": "CODE" }. Rely on code when it is present to handle errors in your script; the wording in error may change.
HTTP statuses
| 400 | The data sent is wrong or missing (parameters, file too large, wrong format). |
| 401 | Missing, wrong or revoked key. |
| 402 | Not enough spirit stones for this action. |
| 403 | Not allowed: the account is blocked, or the action is only available when logged in on the website (managing API keys, admin). |
| 404 | Not found, or it doesn't belong to your account. |
| 409 | Can't be done right now because of the current state (a scene is rendering, a character has no image, the episode is stitching…). See code. |
| 422 | The script doesn't match the format or exceeds a limit, with a list of issues per scene. |
| 429 | Over the rate limit (RATE_LIMITED) or out of character image regenerations for today (DAILY_LIMIT). |
| 500 | Server error. Try again later; if it keeps happening, email contact@lin.vn. |
| 503 | The server isn't ready yet. |
Values of code
| BAD_IMAGE_PATH | 400 | Invalid image file. |
| BAD_OUTPUT_RESOLUTION | 400 | Video resolution must be 720p or 1080p. |
| BAD_SPEED | 400 | Video speed must be between 0.5x and 2x. |
| BAD_TREND_KIND | 400 | Invalid trending video type. |
| CHARACTER_KEY_OVERLAP | 400 | This character key is part of (or contains) another key. Rename it so they can't be confused. |
| DUPLICATE_SCENE | 400 | The scene list contains duplicates. |
| LANGUAGE_NOT_AVAILABLE | 400 | There is no voice for this video language yet. |
| NO_SCENES | 400 | No scenes selected to send. |
| ORDER_MISMATCH | 400 | The episode list doesn't match the project. |
| PROMPT_REQUIRED | 400 | The scene has no prompt yet. |
| VOICE_LANGUAGE_MISMATCH | 400 | The voice is not in the video's language. |
| VOICE_NOT_FOUND | 400 | This voice does not exist or is turned off. |
| INSUFFICIENT_BALANCE | 402 | Not enough spirit stones. |
| BLOCKED | 403 | This account is locked. |
| CHARACTER_NOT_FOUND | 404 | Character not found. |
| EPISODE_NOT_FOUND | 404 | Episode not found. |
| IMAGE_NOT_FOUND | 404 | This character image was not found. |
| PROFILE_NOT_FOUND | 404 | Account not found. |
| PROJECT_NOT_FOUND | 404 | Project not found. |
| SCENE_NOT_FOUND | 404 | Scene not found. |
| TREND_NOT_FOUND | 404 | Video not found. |
| ASPECT_LOCKED | 409 | The aspect ratio is locked once a scene has been sent to render. |
| CAST_LOCKED | 409 | An episode using this character is creating scenes or stitching, so its image can't be changed yet. Wait for it to finish, then try again. |
| CAST_NOT_READY | 409 | A character in this scene has no approved image. Generate or upload an image and approve it before creating the video. |
| CHARACTER_BUSY | 409 | The character image is being generated. |
| CHARACTER_CONFLICT | 409 | The episode and the project have different images for the same character. Choose which one to keep. |
| CHARACTER_EXISTS | 409 | This character key already exists. |
| CHARACTER_LIMIT | 409 | The episode already has the maximum number of characters. |
| CHARACTER_NOT_REVIEWABLE | 409 | The character has no image waiting for review. |
| LAST_SCENE | 409 | An episode must keep at least one scene. |
| PROJECT_BUSY | 409 | The project still has work running (rendering scenes, drawing characters or stitching). Wait for it to finish, then delete. |
| SCENE_BUSY | 409 | The scene is queued or rendering, so it can't be changed right now. |
| SCENE_NOT_REVIEWABLE | 409 | This scene is not ready for review yet. |
| SCENES_NOT_APPROVED | 409 | Some scenes haven't been approved. |
| SCENES_NOT_READY | 409 | Some scenes haven't finished rendering. |
| STITCH_BUSY | 409 | The episode is being stitched. |
| STITCH_UP_TO_DATE | 409 | The current stitched video is already up to date. |
| TREND_BUSY | 409 | The video is being rendered and can't be deleted yet. |
| VOICE_LOCKED | 409 | The voice is locked once a scene has been sent to render. |
| DAILY_LIMIT | 429 | You've used all of today's character image regenerations. |
| RATE_LIMITED | 429 | The API key's rate limit was exceeded. Wait the number of seconds in retryAfter (or the Retry-After header), then call again. |