Wan 3.0 Video API

Base URL: https://api.amazingaitoken.com/v1

Authentication

Create an API key in your dashboard and send it in every request:

Authorization: Bearer aat_live_...

Keep keys secret (server-side only). Revoke a key anytime in the dashboard. Limit: 120 requests per minute per key, 5 videos in progress at once.

Pricing

Videos are paid with Wan credits: 1 credit per second at 480P, 2 at 720P, 4 at 1080P. Billed seconds = output video seconds + any reference video seconds you send. Failed videos cost nothing.

When you start a video we hold the most it can cost (requested duration, or 30 s if you send a reference video or use duration: -1). When it finishes we charge the real cost and return the rest.

Start a video — POST /wan/videos

curl https://api.amazingaitoken.com/v1/wan/videos \
  -H "Authorization: Bearer $AAT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-order-123" \
  -d '{
    "prompt": "A kitten running on a rooftop under the moonlight, cinematic",
    "resolution": "720P",
    "ratio": "16:9",
    "duration": 5
  }'
FieldTypeDescription
promptstringWhat to generate (up to 20,000 characters). Required unless you send media. In reference mode, refer to inputs as "Image 1", "Video 1"…
mediaarrayOptional inputs: {"type": "...", "url": "https://..."}. Types: first_frame, last_frame (image-to-video), reference_image (≤10), reference_video (≤5, total ≤15 s), reference_audio (≤5, total ≤15 s), file or link (document/web page to video). First/last frame cannot be combined with reference_* / file / link. URL must be public, or a data: base64 URI.
resolutionstring480P, 720P or 1080P. Default 1080P.
durationintegerSeconds, 2–30 (default 5). With a reference video, input + output must be ≤ 30. -1 = automatic.
ratiostringadaptive (default), 21:9, 16:9, 4:3, 1:1, 3:4, 9:16.
audiobooleanGenerate sound (default true, same price).
prompt_extendbooleanLet the model improve your prompt (default true; must be true with file/link).
seedinteger-1 (random) or 0–2147483647.
watermarkbooleanAdd a watermark (default false).

The optional Idempotency-Key header makes retries safe: the same key returns the same video instead of starting (and charging) a new one.

Response 201:

{
  "id": "vid_4fK2...",
  "object": "video",
  "status": "queued",
  "model": "wan3.0-video",
  "resolution": "720P",
  "duration": 5,
  "credits_held": 10,
  "credits_charged": null,
  "video_url": null,
  "balance": 170
}

Check a video — GET /wan/videos/{id}

Videos usually take 1–5 minutes. Check every 15–30 seconds until status is succeeded or failed.

curl https://api.amazingaitoken.com/v1/wan/videos/vid_4fK2... -H "Authorization: Bearer $AAT_KEY"

{
  "id": "vid_4fK2...",
  "status": "succeeded",
  "resolution": "720P",
  "credits_held": 0,
  "credits_charged": 10,
  "video_url": "https://...mp4",
  "video_expires_at": "2026-11-07T10:00:00.000Z",
  "usage": { "input_video_seconds": 0, "output_video_seconds": 5, "billed_seconds": 5 },
  "error": null,
  "balance": 170
}

Video links expire after 24 hours. Download and store the MP4 yourself. Status values: queued, running, succeeded, failed (with error.code and error.message; nothing charged).

List your recent videos: GET /wan/videos?limit=20.

Balance — GET /wan/balance

curl https://api.amazingaitoken.com/v1/wan/balance -H "Authorization: Bearer $AAT_KEY"

{ "object": "balance", "credits": 170, "unit": "wan_credit" }

Buy credits — POST /wan/topup

Returns a Stripe payment link. Open it (or send it to the person paying); credits are added automatically after payment. Packages: usd_5 (USD 5 = 90 credits), usd_10 (USD 10 = 180 credits), usd_50 (USD 50 = 900 credits), usd_100 (USD 100 = 1,800 credits), usd_500 (USD 500 = 9,000 credits), usd_1000 (USD 1000 = 18,000 credits). Also listed at GET /wan/packages (no key needed).

curl https://api.amazingaitoken.com/v1/wan/topup \
  -H "Authorization: Bearer $AAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"package": "usd_50"}'

{ "object": "checkout", "package": "usd_50", "price_usd": 50, "credits": 900,
  "checkout_url": "https://checkout.stripe.com/...", "expires_at": "..." }

Python example

import os, time, requests

BASE = "https://api.amazingaitoken.com/v1"
H = {"Authorization": f"Bearer {os.environ['AAT_KEY']}"}

job = requests.post(f"{BASE}/wan/videos", headers=H, json={
    "prompt": "A red sports car driving through a neon city at night",
    "resolution": "720P", "duration": 5,
}).json()

while job["status"] in ("queued", "running"):
    time.sleep(20)
    job = requests.get(f"{BASE}/wan/videos/{job['id']}", headers=H).json()

print(job["status"], job.get("video_url"), job.get("error"))

JavaScript example

const BASE = "https://api.amazingaitoken.com/v1";
const H = { Authorization: `Bearer ${process.env.AAT_KEY}`, "Content-Type": "application/json" };

let job = await fetch(`${BASE}/wan/videos`, {
  method: "POST", headers: H,
  body: JSON.stringify({ prompt: "Drone shot over a tropical island", resolution: "480P", duration: 5 }),
}).then(r => r.json());

while (job.status === "queued" || job.status === "running") {
  await new Promise(r => setTimeout(r, 20000));
  job = await fetch(`${BASE}/wan/videos/${job.id}`, { headers: H }).then(r => r.json());
}
console.log(job.status, job.video_url);

Errors

Errors return a non-2xx status and {"error": {"code": "...", "message": "..."}}.

HTTPcodeMeaning
400invalid_*A field is wrong; the message says which. Model errors (e.g. InvalidParameter) are passed through.
401invalid_api_keyMissing, wrong or revoked key.
402insufficient_creditsNot enough Wan credits for this video. Top up.
404not_foundNo video with that id on your account.
429rate_limited / too_many_active_jobsSlow down, or wait for running videos to finish.
502/503upstream_*The video service had a problem. Nothing charged; retry.