AiWings API reference

Generate and edit images and videos with the best AI models from your own code. Everything AiWings does inside Claude, ChatGPT and Cursor is available here too.

Version v1 · Updated October 31, 2026

Introduction

The AiWings API is a JSON API over HTTPS. You send requests with an API key, AiWings runs the model, stores the result, and gives you back a permanent URL to the file.

All endpoints live under one base URL:

https://aiwings.io/api/v1
  • Requests and responses are JSON. Send Content-Type: application/json with a body.
  • Images and videos are jobs: you start one, then read its status until it's done. See How jobs work.
  • The API uses the same credits as AiWings in your AI agents. There's no separate plan.

Quick start

  1. Create a key on the API page in your dashboard.
  2. Store it as an environment variable, for example AIWINGS_API_KEY.
  3. Create an image. With "wait": true the request returns once the image is ready (up to 60 seconds), so you get the URL in one call.
1curl https://aiwings.io/api/v1/images \
2 -H "Authorization: Bearer $AIWINGS_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "prompt": "A ceramic coffee mug on a sunny kitchen counter",
6 "model": "gpt-image-2.5-flare",
7 "quality": "medium",
8 "aspect_ratio": "1:1",
9 "wait": true
10 }'
POST /v1/imagesShell

The response is an image object:

{
  "id": "8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22",
  "object": "image",
  "status": "succeeded",
  "model": "gpt-image-2.5-flare",
  "quality": "medium",
  "aspect_ratio": "1:1",
  "prompt": "A ceramic coffee mug on a sunny kitchen counter",
  "output": {
    "url": "https://…/generations/8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22.png"
  },
  "credits": 6,
  "error": null,
  "created_at": "2026-10-31T09:41:12.512Z"
}

Authentication

Every request needs your API key in the Authorization header, as a Bearer token:

Authorization: Bearer aiw_live_…
  • Keys start with aiw_live_ followed by 40 random characters.
  • Keys in the URL (for example ?api_key=) are always rejected, so they never end up in logs or browser history.
  • A missing, malformed or revoked key returns 401 authentication_failed.
  • The API does not allow browser (CORS) requests. Call it from your server, a script, or a backend function, never from front-end or mobile app code where anyone could read the key.

Security

AiWings is built so that a key does as little damage as possible if it ever leaks.

ProtectionWhat it means for you
Hashed storageWe store only a SHA-256 hash of each key. The full key is shown once when you create it, and nobody, including us, can read it again.
Instant revokeRevoking a key on the API page blocks it from the very next request. There's no cache to wait for.
Per-key monthly limitGive each key a monthly credit cap. When a key reaches it, new jobs return 403 spend_limit_reached until next month or until you raise the limit.
Rate limitsEach key is limited to 300 requests per minute, 60 of them creating jobs, and your account to 10 jobs rendering at once.
Least privilegeAPI keys can generate, read your generations and change defaults. They can't create keys, see billing details or change your plan.
HTTPS onlyKeys only travel over TLS, and only in the Authorization header.

Recommended practice:

  • Use one key per app or environment (production, staging, a script), so you can revoke one without touching the others.
  • Set a monthly limit on every key, sized to what that app should ever spend.
  • Keep keys in environment variables or a secrets manager. Never commit them to git.
  • To rotate a key: create a new one, deploy it, then revoke the old one. You can have up to 10 active keys.
  • If a key leaks, revoke it right away and email Mejed@templyo.io.
Output URLs are public but unguessable, like a share link. Anyone you give a URL to can open the file.

How jobs work

Images take seconds and videos can take minutes, so every generation runs as a job. Creating one returns right away with a job object whose status is one of:

StatusMeaning
processingThe model is rendering, or the file is being saved.
succeededDone. output.url is the permanent URL to the file.
failedThe model couldn't make it. error.message says why, and the credits are refunded automatically.

Three ways to get the result:

  • Wait on create. Add "wait": true (or a number of seconds, up to 60) to the request body. Best for images.
  • Long-poll. Call GET /v1/images/{id}?wait=30 or GET /v1/videos/{id}?wait=30. The request returns as soon as the job finishes, or after 30 seconds with the current status. Best for videos.
  • Poll. Call the GET endpoint every few seconds without wait.

Jobs keep running even if your request disconnects. A job started from your code also shows up in your dashboard library.

Idempotency

Networks fail. To retry a create request safely, send an Idempotency-Key header with a unique value (a UUID works well, 1–100 characters of letters, numbers, - _ : .).

If a job with that key already exists on your account, the API returns that job instead of starting a new one, so you're never charged twice. Replayed responses have the header Idempotent-Replayed: true and status 200 instead of 201.

curl -X POST "https://aiwings.io/api/v1/images" \
  -H "Authorization: Bearer $AIWINGS_API_KEY" \
  -H "Idempotency-Key: 9b2f4c1e-sneaker-hero" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Studio photo of a red sneaker",
    "wait": true
  }'

Errors

Errors use standard HTTP status codes and always have the same body. Include the request_id when you contact support. Every response also carries it in the X-Request-Id header.

{
  "error": {
    "type": "invalid_request",
    "message": "GPT Image 2.5 Flare quality must be one of: low, medium, high, xhigh, max.",
    "param": "quality",
    "request_id": "req_4c1f0e6a9b2d4e7f8a1b2c3d4e5f6a7b"
  }
}
StatustypeWhen
400invalid_requestA field is missing, unknown, or not allowed for that model. param names the field.
401authentication_failedMissing, malformed or revoked API key.
402insufficient_creditsYour balance can't cover this job. Top up in the dashboard.
402subscription_requiredGenerating needs an active plan.
403spend_limit_reachedThis key reached its monthly credit limit.
404not_foundNo job with that id on your account.
413payload_too_largeThe JSON body is too big (64 KB max).
429rate_limitedToo many requests for this key. Retry after the Retry-After header.
429too_many_jobs10 jobs are already rendering. Wait for one to finish.
502generation_failedThe model couldn't start the job. Credits were refunded. Retry shortly.
503service_unavailableTemporary problem on our side. Retry with backoff.
500internal_errorUnexpected error. Retry, and contact support with the request_id if it repeats.

Unknown fields are rejected rather than ignored, so a typo like "resoltion" fails loudly instead of quietly using a default.

Rate limits

LimitValueScope
All requests300 / minutePer key
Requests that create or change something60 / minutePer key
Jobs rendering at the same time10Per account (API jobs)

Every response tells you where you stand:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1761903720   # unix seconds when the window resets

On 429, wait for the number of seconds in Retry-After, then retry. Need higher limits? Email Mejed@templyo.io.

Credits

  • The API draws from the same credit balance as your AI agents and the dashboard.
  • Images cost a fixed number of credits per image, by model and quality. Videos cost credits per second, by model and resolution. Jobs with a reference video use a higher per-second rate.
  • Credits are charged when a job starts. Failed jobs are refunded automatically.
  • Each job returns what it cost in credits. GET /v1/models lists every price and GET /v1/account shows your balance.

Full price tables are under Image models and Video models, and plans are on the credits page.

Create an image

POST/v1/images

Generates a new image from a prompt, or edits images: pass reference images (your product, a character, a style) or the id of an earlier image to change it.

Body

promptstring · required
What to create, up to 4,000 characters. For edits, describe the change.
modelstring · optional
Model id, e.g. gpt-image-2.5-flare. Defaults to your saved default. See Image models.
qualitystring · optional
Model-specific: low … max for GPT Image models, 1K / 2K / 4K for Nano Banana models. Sets the price.
aspect_ratiostring · default "1:1"
e.g. 1:1, 3:2, 16:9, 9:16. Each model lists what it supports.
reference_imagesstring[] · optional
Public URLs of images to use as references (product, character, style). Use uploads for local files. The maximum depends on the model (max_reference_images in GET /v1/models); text-only models (Imagen 4, Flux Fast) have 0 and reject references.
source_generation_idstring · optional
Id of an earlier image to edit. It's used as the first reference.
waitboolean | number · default false
Hold the request until the image is ready, up to 60 seconds. true = 60.

Headers

Idempotency-Keystring · optional
Makes retries safe. See Idempotency.

Returns 201 with an image object.

Edit with a reference image

curl -X POST "https://aiwings.io/api/v1/images" \
  -H "Authorization: Bearer $AIWINGS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Place this bottle on a mossy rock in a misty forest, soft morning light",
    "model": "nano-banana-pro",
    "quality": "2K",
    "aspect_ratio": "4:5",
    "reference_images": [
      "https://example.com/bottle.png"
    ],
    "wait": true
  }'

Change an earlier result

curl -X POST "https://aiwings.io/api/v1/images" \
  -H "Authorization: Bearer $AIWINGS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Same scene, but at night with warm string lights",
    "source_generation_id": "8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22",
    "wait": true
  }'

Get an image

GET/v1/images/{id}

Returns the current state of an image job. Add ?wait=30 to hold the request until it finishes (max 60).

curl "https://aiwings.io/api/v1/images/8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22?wait=30" \
  -H "Authorization: Bearer $AIWINGS_API_KEY"

Create a video

POST/v1/videos

Starts a video job: text to video, animate an image (first frame, optional last frame), or guide the video with reference images and clips. Videos include generated audio unless you turn it off.

Body

promptstring · depends on model
What happens in the video, up to 4,000 characters. Required for some models, see prompt_required in GET /v1/models.
modelstring · optional
Video model id, e.g. seedance-2.0. Defaults to your saved default.
resolutionstring · optional
e.g. 480p, 720p, 1080p. Sets the per-second price.
durationinteger · optional
Length in seconds, within the model's min and max.
aspect_ratiostring · optional
e.g. 16:9, 9:16, 1:1, adaptive (match the first frame).
audioboolean · default true
Generate a soundtrack and sound effects.
formatstring · default "mp4"
Output file format. Some models also offer mov.
first_framestring · optional
Public URL of an image the video starts from.
source_generation_idstring · optional
Id of one of your images to use as the first frame (instead of first_frame).
last_framestring · optional
Public URL of an image the video ends on. Needs a first frame.
reference_imagesstring[] · optional
Public image URLs for characters, products, style or scene. Mention them in the prompt as [Image1], [Image2]…
reference_videosstring[] · optional
Public MP4/MOV URLs for motion, camera or editing style. Uses the higher reference-video rate.
waitboolean | number · default false
Hold the request up to 60 seconds. Most videos take longer, so long-poll the GET endpoint instead.
First and last frames can't be combined with reference images. Pick one approach per video. Some models also can't mix frames with reference videos: the error message tells you exactly what to change.
1# 1. Start the job
2curl https://aiwings.io/api/v1/videos \
3 -H "Authorization: Bearer $AIWINGS_API_KEY" \
4 -H "Content-Type: application/json" \
5 -H "Idempotency-Key: launch-teaser-001" \
6 -d '{
7 "prompt": "Slow dolly shot of a glass bottle on wet sand at sunset, waves rolling in",
8 "model": "seedance-2.0",
9 "resolution": "720p",
10 "duration": 5,
11 "aspect_ratio": "16:9",
12 "audio": true
13 }'
14
15# 2. Poll until status is "succeeded" (or "failed")
16curl "https://aiwings.io/api/v1/videos/VIDEO_ID?wait=30" \
17 -H "Authorization: Bearer $AIWINGS_API_KEY"
POST /v1/videosShell

Returns 201 with a video object:

{
  "id": "2b9e6d10-7c3a-4f8e-b1d2-55a0c9e4f871",
  "object": "video",
  "status": "processing",
  "model": "seedance-2.0",
  "resolution": "720p",
  "duration": 5,
  "aspect_ratio": "16:9",
  "audio": true,
  "format": "mp4",
  "prompt": "Slow dolly shot of a glass bottle on wet sand at sunset",
  "output": null,
  "credits": 115,
  "error": null,
  "created_at": "2026-10-31T09:45:03.020Z"
}

Get a video

GET/v1/videos/{id}

Returns the current state of a video job. Add ?wait=30 to long-poll: the request returns as soon as the video is ready, or after 30 seconds (max 60).

curl "https://aiwings.io/api/v1/videos/2b9e6d10-7c3a-4f8e-b1d2-55a0c9e4f871?wait=30" \
  -H "Authorization: Bearer $AIWINGS_API_KEY"

List generations

GET/v1/generations

Your images and videos, newest first, from the API, your AI agents and the dashboard.

Query

typestring · optional
image or video.
statusstring · optional
processing, succeeded or failed.
limitinteger · default 20
1 to 100.
cursorstring · optional
next_cursor from the previous page.
{
  "object": "list",
  "data": [
    {
      "id": "8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22",
      "object": "image",
      "status": "succeeded",
      "model": "gpt-image-2.5-flare",
      "quality": "medium",
      "aspect_ratio": "1:1",
      "prompt": "A ceramic coffee mug on a sunny kitchen counter",
      "output": {
        "url": "https://…/generations/8f1c2a4e-5b7d-4e2f-9a31-0c6d8e7f1b22.png"
      },
      "credits": 6,
      "error": null,
      "created_at": "2026-10-31T09:41:12.512Z"
    },
    "…"
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMC0zMVQwOTo0MToxMi41MTJa…"
}
GET/v1/generations/{id}

Any single generation, image or video. Supports ?wait like the endpoints above.

Upload a file

POST/v1/uploads

For files on your machine or server. Ask for an upload URL, PUT the bytes to it, then pass the returned url anywhere a URL is accepted (reference_images, first_frame, last_frame, reference_videos). Files that are already public on the web can be passed directly.

Body

content_typestring · required
One of image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime.
size_bytesinteger · optional
File size, checked against the 50 MB limit.
filenamestring · optional
For your reference.
{
  "id": "upl_6f1d2c3b4a5e6f708192a3b4",
  "object": "upload",
  "filename": "product.png",
  "content_type": "image/png",
  "upload_url": "https://…/object/upload/sign/…?token=…",
  "upload_method": "PUT",
  "upload_headers": {
    "Content-Type": "image/png"
  },
  "url": "https://…/api-uploads/upl_6f1d2c3b4a5e6f708192a3b4.png",
  "expires_at": "2026-10-31T11:41:12.512Z"
}

The upload URL works once and expires after 2 hours. Uploaded files are public but unguessable, like outputs.

1# 1. Ask for an upload URL
2curl https://aiwings.io/api/v1/uploads \
3 -H "Authorization: Bearer $AIWINGS_API_KEY" \
4 -H "Content-Type: application/json" \
5 -d '{ "content_type": "image/png", "filename": "product.png" }'
6
7# 2. PUT the file to upload_url from the response
8curl -X PUT "UPLOAD_URL" \
9 -H "Content-Type: image/png" \
10 --data-binary @product.png
11
12# 3. Use the returned "url" as a reference
13curl https://aiwings.io/api/v1/images \
14 -H "Authorization: Bearer $AIWINGS_API_KEY" \
15 -H "Content-Type: application/json" \
16 -d '{ "prompt": "Put this product on a marble table, soft daylight", "reference_images": ["URL"] }'
POST /v1/uploadsShell

List models

GET/v1/models

Every model with its options and credit prices. Filter with ?type=image or ?type=video. Use it to build model pickers or to check prices before you start a job.

{
  "object": "list",
  "data": [
    {
      "id": "nano-banana-2",
      "object": "model",
      "type": "image",
      "name": "Nano Banana 2",
      "description": "Best quality-per-credit (Gemini 3.1 Flash Image)",
      "qualities": [
        {
          "value": "1K",
          "credits": 8
        },
        {
          "value": "2K",
          "credits": 13
        },
        {
          "value": "4K",
          "credits": 19
        }
      ],
      "default_quality": "1K",
      "aspect_ratios": [
        "1:1",
        "2:3",
        "3:2",
        "…"
      ],
      "max_reference_images": 14
    },
    "…"
  ]
}

Defaults

GET/v1/defaults
PATCH/v1/defaults

Defaults are used whenever a request leaves out model, quality, resolution, duration, aspect_ratio or audio. They're shared with your AI agents and the dashboard. PATCH only changes the fields you send.

curl -X PATCH "https://aiwings.io/api/v1/defaults" \
  -H "Authorization: Bearer $AIWINGS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": {
      "model": "nano-banana-2",
      "quality": "2K"
    },
    "video": {
      "resolution": "1080p",
      "duration": 8
    }
  }'
{
  "object": "defaults",
  "image": {
    "model": "nano-banana-2",
    "quality": "2K"
  },
  "video": {
    "model": "seedance-2.0",
    "resolution": "1080p",
    "duration": 8,
    "aspect_ratio": "16:9",
    "audio": true
  }
}

Account

GET/v1/account

Your credit balance, plan, and how much this key has spent this month.

{
  "object": "account",
  "credits": 1840,
  "plan": "sub-pro",
  "subscription_status": "active",
  "renews_at": "2026-11-28T00:00:00Z",
  "can_generate": true,
  "api_key": {
    "name": "Shopify sync",
    "monthly_credit_limit": 1000,
    "credits_used_this_month": 212
  }
}

Image object

Fields

idstring
Job id.
object"image"
Always image.
statusstring
processing, succeeded or failed.
modelstring
Model id used.
qualitystring
Quality used.
aspect_ratiostring
Aspect ratio used.
promptstring
The prompt.
outputobject | null
When succeeded: { url }, a permanent URL to the PNG.
creditsinteger
Credits charged. Refunded if the job fails.
errorobject | null
When failed: { message, refunded }.
created_atstring
ISO 8601 timestamp.

Video object

Fields

idstring
Job id.
object"video"
Always video.
statusstring
processing, succeeded or failed.
modelstring
Model id used.
resolutionstring
Resolution used.
durationinteger
Length in seconds.
aspect_ratiostring
Aspect ratio used.
audioboolean
Whether audio was generated.
formatstring
mp4 or mov.
promptstring
The prompt (may be empty for some image-to-video jobs).
outputobject | null
When succeeded: { url, format }.
creditsinteger
Credits charged. Refunded if the job fails.
errorobject | null
When failed: { message, refunded }.
created_atstring
ISO 8601 timestamp.

Image models

Credits per image. Live values are always in GET /v1/models?type=image.

Model idNameQuality → creditsMax references
gpt-image-2.5-flareGPT Image 2.5 FlareLow 2 · Medium 6 · High 16 · Xhigh 31 · Max 6310
gpt-image-2.5-sunburstGPT Image 2.5 SunburstLow 2 · Medium 6 · High 16 · Xhigh 31 · Max 6310
gpt-image-2GPT Image 2Low 2 · Medium 6 · High 1610
gpt-image-1.5GPT Image 1.5Low 2 · Medium 7 · High 1710
nano-bananaNano Banana1K 53
nano-banana-2Nano Banana 21K 8 · 2K 13 · 4K 1914
nano-banana-proNano Banana Pro1K 19 · 2K 19 · 4K 3814
imagen-4-ultraImagen 4 Ultra1K 8 · 2K 80
imagen-4Imagen 41K 5 · 2K 50
imagen-4-fastImagen 4 Fast1K 30
seedream-5-liteSeedream 5 Lite2K 5 · 3K 514
grok-imagineGrok Imagine1K 31
flux-fastFlux Fast1K 10

Video models

Credits per second of video. Live values are always in GET /v1/models?type=video.

Model idNameResolution → credits/sWith reference videoDuration
seedance-2.0Seedance 2.0480p 10 · 720p 23 · 1080p 57 · 4k 125480p 13 · 720p 28 · 1080p 69 · 4k 1574–15s
seedance-2.5Seedance 2.5480p 13 · 720p 29480p 54 · 720p 1214–30s

Example: a 5-second seedance-2.0 video at 720p costs 23 × 5 = 115 credits.

Changelog

DateChange
October 31, 2026v1 released: images, videos, uploads, generations, models, defaults, account.