Skip to content

仕様API reference

Every endpoint, documented completely.

Base URL https://animeapi.ai. JSON in, JSON out. Images are synchronous: the response arrives when the image exists. Videos are jobs: start one, then poll it until the MP4 is ready.

01Authentication

Every request needs an API key from Dashboard → API keys in the Authorization header:

header
Authorization: Bearer ank_your_key_here
  • Keys are ank_ followed by 64 hex characters. We store only a SHA-256 hash, so a key is shown once when you create it.
  • Revoke a key from the dashboard at any time; requests with it then return 401 immediately.
  • Keep keys on the server. Anyone holding a key can spend your balance.

02POST /api/generate

Generate one image. The body is JSON:

Request body fields
FieldTypeDefaultDescription
promptstringrequiredWhat to draw, in plain English. Trimmed. Max 1,000 characters.
model"anime" | "ultra" | "ultra-max""anime"Which model draws it. See models.
orientation"portrait" | "square" | "landscape""portrait"Aspect ratio. Exact pixel sizes depend on the model.
enhancebooleantrueAnime model only. Rewrites your prompt into Danbooru tags before generating. Ultra tiers ignore it.
allowNSFWbooleantrueAnime model only. When false, images flagged as NSFW fail with 500 and are refunded. Ultra tiers ignore it and use the provider’s moderation.

Every field

bash
curl https://animeapi.ai/api/generate \
  -H "Authorization: Bearer $ANIMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a girl with a red umbrella at a rainy bus stop",
    "model": "anime",
    "orientation": "landscape",
    "enhance": true,
    "allowNSFW": false
  }'

An ultra request

bash
curl https://animeapi.ai/api/generate \
  -H "Authorization: Bearer $ANIMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "anime illustration, a cafe chalkboard that reads OPEN LATE", "model": "ultra", "orientation": "square"}'

In your language

curl https://animeapi.ai/api/generate \
  -H "Authorization: Bearer $ANIMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a girl with a red umbrella at a rainy bus stop", "model": "anime", "orientation": "portrait"}'

03Response

200 OK with:

200 OK · example
{
  "image_url": "https://…/5e1c9a4f.webp",
  "enhanced_prompt": "masterpiece, best quality, absurdres, 1girl, solo, red_umbrella, holding_umbrella, bus_stop, rain, night, …",
  "balance_usd": 9.991,
  "generation_time_ms": 4121
}
Response fields
FieldTypeAlways presentDescription
image_urlstringyesURL of the image. WebP from the anime model, PNG from ultra tiers.
enhanced_promptstringyesThe prompt the model actually received: Danbooru tags when enhancement ran on the anime model, your prompt plus the anime style on ultra tiers, otherwise your prompt as sent.
balance_usdnumberyesYour balance after this charge. A raw float that may show noise like 9.991000000000001; round it for display.
generation_time_msnumberyesMilliseconds spent generating, including enhancement. Excludes network time to you.

04Models & pricing

Prices are per successful image (videos are priced per second, see below). Add $5–$1,000 at a time on Billing; the balance never expires.

Models, prices, sizes and measured speed
ModelPrice (any orientation)Sizes (P · S · L)FormatMeasured median
animeFast and cheap. Best at characters. Your prompt is rewritten into Danbooru tags first.$0.003832×1280 · 1024×1024 · 1280×832WebP4.3s
ultraFollows long sentences and renders legible text.$0.011024×1536 · 1024×1024 · 1536×1024PNG10.5s
ultra-maxUltra with more care: finer detail, cleaner hands, real typography.$0.021024×1536 · 1024×1024 · 1536×1024PNG11.5s
  • anime: best for characters. Understands tags; can’t render legible text; strongly prefers drawing a person.
  • ultra: follows long, compositional sentences and renders text. An anime style is added to every prompt, so plain descriptions come out as anime.
  • ultra-max: ultra with more care: finer detail, better hands and typography.

Latency measured end to end on 2026-09-24 over 16 anime, 5 ultra and 5 ultra-max calls. Not a guarantee.

05Prompt enhancement

The anime model was trained on booru tags, not sentences. With enhance: true (the default), a fast language model rewrites your prompt into Danbooru-style tags before generation, adding about a second. The tags come back in enhanced_prompt.

  • To reuse a look exactly, send a previous enhanced_prompt back as the prompt with enhance: false.
  • If you already write tags, turn enhancement off. It occasionally adds contradictory tags (for example 1girl next to no_humans).
  • Ultra and ultra-max don’t use tags: they keep your sentence and append an anime style, shown in enhanced_prompt.

06POST /api/videos

Start one anime video: text-to-video, or animated from a first and/or last frame you supply. Rendering takes a while, so this returns 202 with a job id straight away; poll GET /api/videos/{id} until it finishes. The price is charged when the job starts and refunded automatically if it fails.

Video request body fields
FieldTypeDefaultDescription
promptstringrequiredWhat happens in the clip, in plain English. Trimmed. Max 1,000 characters. An anime style is added automatically.
resolution"480p" | "768p""768p"Output resolution. Priced per second, see pricing.
durationinteger5Length in seconds, 5 to 15.
orientation"portrait" | "square" | "landscape""landscape"9:16, 1:1 or 16:9. When first_frame is set, the image sets the shape instead.
enhancebooleantrueLets the video model expand your prompt with detail before rendering.
first_framestringnoneImage the clip starts on: an http(s) URL or a base64 data URI (data:image/png;base64,…), up to 10 MB.
last_framestringnoneImage the clip ends on. Same format.

Send neither frame for text-to-video. Send one or both to animate from, toward, or between your own images, for example a character you generated with /api/generate.

Text to video

bash
curl https://animeapi.ai/api/videos \
  -H "Authorization: Bearer $ANIMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a girl with a red umbrella waits at a rainy bus stop, then looks up as the bus pulls in",
    "resolution": "480p",
    "duration": 5,
    "orientation": "landscape"
  }'

From a first frame

bash
curl https://animeapi.ai/api/videos \
  -H "Authorization: Bearer $ANIMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "she rides down the hill toward the sea, hair and ribbon blowing in the wind",
    "first_frame": "https://animeapi.ai/gen/wall-bike-sea.webp",
    "resolution": "480p",
    "duration": 5
  }'

202 Accepted

202 Accepted · example
{
  "id": "j57c2x9k…",
  "status": "processing",
  "poll_url": "https://animeapi.ai/api/videos/j57c2x9k…",
  "enhanced_prompt": "a girl with a red umbrella waits at a rainy bus stop, then looks up as the bus pulls in, anime style, …",
  "resolution": "480p",
  "duration": 5,
  "orientation": "landscape",
  "cost_usd": 0.08,
  "balance_usd": 9.92
}
Video job fields returned on creation
FieldTypeAlways presentDescription
idstringyesThe job id. Poll it with GET /api/videos/{id}.
status"processing"yesAlways processing on creation.
poll_urlstringyesThe full GET URL for this job.
enhanced_promptstringyesYour prompt plus the anime style, as sent to the video model. With enhance on, the model may expand it further.
resolution, duration, orientationstring · number · stringyesThe settings used, with defaults filled in.
cost_usdnumberyesWhat this video costs. Already charged.
balance_usdnumberyesYour balance after the charge. A raw float; round it for display.

Pricing

Per requested second, charged up front, refunded if the video fails.

Video prices and sizes by resolution
ResolutionPer second5s clip15s clipSizes (P · S · L)
480p$0.016$0.08$0.24480×832 · 480×480 · 832×480
768p$0.04$0.20$0.60768×1344 · 768×768 · 1344×768

Sizes are nominal. With a first frame, the image sets the canvas.

07GET /api/videos/{id}

Poll with the same key, about every 5 seconds, until status is succeeded or failed. Only the account that created a video can read it.

bash
curl https://animeapi.ai/api/videos/$VIDEO_ID \
  -H "Authorization: Bearer $ANIMEAPI_KEY"
200 OK · while rendering
{
  "id": "j57c2x9k…",
  "status": "processing",
  "video_url": null,
  "prompt": "a girl with a red umbrella waits at a rainy bus stop, then looks up as the bus pulls in",
  "enhanced_prompt": "a girl with a red umbrella waits at a rainy bus stop, then looks up as the bus pulls in, anime style, …",
  "resolution": "480p",
  "duration": 5,
  "orientation": "landscape",
  "first_frame": false,
  "last_frame": false,
  "cost_usd": 0.08,
  "refunded": false,
  "generation_time_ms": null,
  "error": null,
  "created_at": "2026-09-29T09:14:03.512Z"
}
Video status fields
FieldTypeAlways presentDescription
status"processing" | "succeeded" | "failed"yesWhere the job is.
video_urlstring | nullyesThe MP4 once succeeded, otherwise null.
prompt, enhanced_promptstringyesWhat you sent, and what the video model received.
resolution, duration, orientationstring · number · stringyesThe settings used.
first_frame, last_framebooleanyesWhether the job was started from those frames.
cost_usdnumberyesWhat the video cost.
refundedbooleanyestrue when the job failed and the charge went back to your balance.
generation_time_msnumber | nullyesTime from start to finished file, once succeeded.
errorstring | nullyesWhy it failed. See failed video jobs.
created_atstringyesISO 8601 timestamp.
  • Videos are MP4, 24 fps, with generated sound.
  • A failed job has refunded: true; start a new one if you want to retry. Don’t start duplicates while one is still processing: each start is charged.

Start and wait, in your language

// video.mjs · Node 18+ · run: node video.mjs
const API = "https://animeapi.ai/api/videos";
const headers = {
  Authorization: `Bearer ${process.env.ANIMEAPI_KEY}`,
  "Content-Type": "application/json",
};

// 1. Start the job. The price is charged now and refunded if it fails.
const res = await fetch(API, {
  method: "POST",
  headers,
  body: JSON.stringify({
    prompt: "a girl with a red umbrella waits at a rainy bus stop, then looks up as the bus pulls in",
    resolution: "480p",
    duration: 5,
    orientation: "landscape",
  }),
});
let video = await res.json();
if (!res.ok) throw new Error(`${res.status} ${video.code ?? ""}: ${video.error}`);
console.log(`started ${video.id}, charged ${video.cost_usd} USD`);

// 2. Poll every 5 seconds until it finishes.
while (video.status === "processing") {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  const poll = await fetch(`${API}/${video.id}`, { headers });
  video = await poll.json();
  if (!poll.ok) throw new Error(`${poll.status} ${video.code ?? ""}: ${video.error}`);
}

if (video.status === "failed") throw new Error(`Failed and refunded: ${video.error}`);
console.log(video.video_url);

08Errors

Errors are JSON with an error message and, for most, a machine-readable code. Validation errors happen before anything is charged. If generation fails after charging, the charge is refunded automatically.

402 Payment Required
{ "error": "Insufficient balance. Please add funds to your account.", "code": "INSUFFICIENT_BALANCE" }

POST /api/generate

Errors from POST /api/generate
StatuscodeerrorWhenCharged
400—Invalid JSON bodyThe body isn't valid JSON.No
400—Missing 'prompt' field in request bodyprompt is missing or empty.No
400—Prompt exceeds maximum length of 1000 charactersprompt is longer than 1,000 characters.No
400—Invalid model. Must be 'anime', 'ultra', or 'ultra-max'Unknown model.No
400—Invalid orientation. Must be 'portrait', 'square', or 'landscape'Unknown orientation.No
400MODERATION_BLOCKEDYour prompt was blocked by the content safety system. Please revise it and try again.Ultra tiers: the provider's safety system refused the prompt.Refunded
401—Missing or invalid Authorization header. Use: Bearer ank_xxxxxNo Authorization header, or not in Bearer form.No
401—Invalid API key format. Keys should start with 'ank_'The token doesn't start with ank_.No
401INVALID_KEYInvalid API keyKey not found.No
401INVALID_KEYAPI key has been revokedThe key was revoked in the dashboard.No
402INSUFFICIENT_BALANCEInsufficient balance. Please add funds to your account.Balance is below the price of the requested image.No
500GENERATION_FAILED(message from the image provider) or Internal server errorGeneration failed upstream, or the request couldn't be processed.Refunded

POST /api/videos

Errors from POST /api/videos
StatuscodeerrorWhenCharged
400—Invalid JSON bodyThe body isn't valid JSON.No
400—Missing 'prompt' field in request bodyprompt is missing or empty.No
400—Prompt exceeds maximum length of 1000 charactersprompt is longer than 1,000 characters.No
400—Invalid resolution. Must be '480p' or '768p'Unknown resolution.No
400—Invalid duration. Must be a whole number of seconds from 5 to 15duration isn't an integer in range.No
400—Invalid orientation. Must be 'portrait', 'square', or 'landscape'Unknown orientation.No
400INVALID_FRAME'first_frame' must be an image URL or a base64 data URINot an http(s) URL or a data:image/…;base64 URI. Same for last_frame.No
400INVALID_FRAME'first_frame' is larger than 10 MBA data URI decodes to more than 10 MB. Same for last_frame.No
400INVALID_FRAMECouldn't download first_frame from <url>The frame URL couldn't be reached. Same for last_frame.No
400INVALID_FRAMECouldn't download first_frame: HTTP <status>The frame URL answered with an error status. Same for last_frame.No
400INVALID_FRAMEfirst_frame must be an image (got <content-type>)The frame URL isn't served as image/*. Same for last_frame.No
400INVALID_FRAMEfirst_frame is larger than 10 MBThe downloaded frame is over 10 MB. Same for last_frame.No
401—Missing or invalid Authorization header. Use: Bearer ank_xxxxxNo Authorization header, or not in Bearer form.No
401—Invalid API key format. Keys should start with 'ank_'The token doesn't start with ank_.No
401INVALID_KEYInvalid API keyKey not found.No
401INVALID_KEYAPI key has been revokedThe key was revoked in the dashboard.No
402INSUFFICIENT_BALANCEInsufficient balance. Please add funds to your account.Balance is below the price of the requested video.No
500GENERATION_FAILEDThe prompt or a frame was blocked by the content safety system. Please revise it and try again.The video model's safety system refused the prompt or a frame.Refunded
500GENERATION_FAILEDThe video couldn't be generated. The charge was refunded; retrying once is fine.The job couldn't be started.Refunded
500GENERATION_FAILEDInternal server errorThe request couldn't be processed.No

GET /api/videos/{id}

Errors from GET /api/videos/{id}
StatuscodeerrorWhenCharged
401—Missing or invalid Authorization header. Use: Bearer ank_xxxxxNo Authorization header, not in Bearer form, or the token doesn't start with ank_.No
401INVALID_KEYInvalid API keyKey not found or revoked.No
404NOT_FOUNDVideo not foundNo video with that id, or it belongs to another account.No

Failed video jobs

A video that fails while rendering isn’t an HTTP error: GET /api/videos/{id} returns 200 with status: "failed", refunded: true and one of these in error. The charge is already back in your balance.

Messages in the error field of a failed video
StatuscodeerrorWhenCharged
200—The prompt or a frame was blocked by the content safety system. Please revise it and try again.The video model's safety system refused the prompt or a frame.Refunded
200—The video couldn't be generated. The charge was refunded; retrying once is fine.Rendering failed.Refunded
200—The video took too long to render. The charge was refunded.The job was still running after 30 minutes.Refunded

Retrying

Only a 500 (or a failed video job) is worth retrying automatically; you were refunded. 400, 401, 402 and 404 won’t change on retry.

retry.py
import os
import time
import requests

def generate(prompt: str, model: str = "anime", attempts: int = 3) -> dict:
    for attempt in range(1, attempts + 1):
        res = requests.post(
            "https://animeapi.ai/api/generate",
            headers={"Authorization": f"Bearer {os.environ['ANIMEAPI_KEY']}"},
            json={"prompt": prompt, "model": model, "allowNSFW": False},
            timeout=180,
        )
        data = res.json()
        if res.ok:
            return data
        # 500 means the provider failed and you were refunded: safe to retry.
        if res.status_code == 500 and attempt < attempts:
            time.sleep(2 * attempt)
            continue
        # 400/401/402 won't fix themselves by retrying.
        raise RuntimeError(f"{res.status_code} {data.get('code', '')}: {data['error']}")
    raise RuntimeError("unreachable")

if __name__ == "__main__":
    print(generate("a girl with a red umbrella at a rainy bus stop")["image_url"])

09Limits

  • No daily or per-minute cap. Generate as many images and videos as your balance covers.
  • If you ever get a 429, back off and retry.
  • Prompts up to 1,000 characters.
  • One image per request. For batches, send requests in parallel from your server.
  • One video per job, 5 to 15 seconds. Jobs run in parallel; frames up to 10 MB each.

10Image & video URLs

  • Anime images are WebP files on our generation provider’s CDN. Download anything you want to keep; don’t treat the URL as permanent storage.
  • Ultra and ultra-max images are PNG files in AnimeAPI’s storage.
  • Videos are MP4 files in AnimeAPI’s storage.
  • All are public URLs that anyone with the link can open.

11Demo endpoint

The homepage demo uses a public endpoint with no key: anime model, portrait, enhancement on, NSFW off, and 3 images per IP per day. It’s for trying things, not for production.

POST /api/demo/generate
curl https://animeapi.ai/api/demo/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a knight cat drinking tea in a sunflower field"}'
  • Body: prompt only, up to 500 characters.
  • Response: image_url, enhanced_prompt, generation_time_ms and demo_remaining.
  • Over the limit: 429 with code: "RATE_LIMITED". A failed generation still uses one of the three.

12CORS & browsers

Responses include Access-Control-Allow-Origin: *, and preflight allows Content-Type and Authorization. That makes local tools and prototypes easy, but don’t ship an API key in public browser code: call AnimeAPI from your server and pass the image or video URL to the client.