Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
contact:
email: support@azurade.com
name: Azurade AI support
description: 'Image and video generation, prompt tools and account access for Azurade AI.
Credits: one balance per account, shared with the web app, same prices. Credits do not expire and are not reset by any billing cycle. A failed generation is refunded automatically. Prices are in credits; the model catalogue carries the price of a default request and POST /api/v2/generations/estimate the exact price of a specific one.
Errors: every non-2xx body is {"error": , "code": }. Codes worth handling: unknown_model, validation_failed, insufficient_credits (402; POST /api/v2/checkout returns a link for the account holder to buy more), prompt_rejected (400, revise the prompt, do not retry it unchanged), moderation_unavailable and enhance_unavailable (503, safe to retry), generation_failed (502, the job could not be started and nothing was charged; its id is in the body and GET /api/v2/generations/{id} carries the reason), not_found (404, also for records that belong to another account).
Generations are asynchronous: POST answers 202 with an id, GET /api/v2/generations/{id} moves from pending to completed or failed, and completed carries the output files. The files are attached a moment after the status turns completed, so poll until status is failed, or completed with a non-empty outputs array.'
title: Azurade AI Generations API
version: '2'
servers:
- url: https://azurade.com
tags:
- description: Submit image and video jobs, price them before submitting, and poll them to completion.
name: Generations
paths:
/api/v2/generations:
get:
description: Your generations, newest first, optionally only one status, model or type. Page with next_cursor. An unknown filter value answers 400 invalid_query.
operationId: listGenerations
parameters:
- in: query
name: limit
schema:
default: 20
maximum: 100
minimum: 1
type: integer
- description: next_cursor from the previous page, unchanged
in: query
name: cursor
schema:
type: string
- description: Only generations in this status
in: query
name: status
schema:
enum:
- pending
- completed
- failed
- stalled
- canceled
type: string
- description: Only generations of this model id
in: query
name: model
schema:
type: string
- description: Only image or only video generations
in: query
name: type
schema:
enum:
- image
- video
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationList'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Invalid request
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Missing or invalid credentials
security:
- ApiKeyAuth: []
- SessionAuth: []
summary: List generations
tags:
- Generations
post:
description: 'Submits an image or video generation. The model''s type decides which; parameters beyond model and prompt vary per model (see GET /api/v2/models/{id}). Credits are reserved when the job is accepted and refunded automatically if it fails; a model priced per image refunds the images it does not deliver. Send an idempotency_key so a retry after a timeout returns the first job, marked idempotent_replay, instead of charging twice. Every prompt is screened against the content policy first, and every input URL is fetched once (its first byte): one that does not download, or is a web page or text rather than a file, answers 400 validation_failed naming the field, before anything is charged. A job that cannot be started answers 502 generation_failed with its id and charges nothing; GET /api/v2/generations/{id} then carries the reason.'
operationId: createGeneration
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationRequest'
required: true
responses:
'202':
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationAccepted'
description: Accepted
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Invalid request
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Missing or invalid credentials
'402':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Insufficient credits
'409':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: 'idempotency_in_progress: a create with the same idempotency_key is still being submitted; retry in a few seconds'
'422':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: 'idempotency_key_reused: the idempotency_key was first sent with a different request; send a new key'
'502':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: 'generation_failed: the job could not be started and nothing was charged. id names the failed job; GET /api/v2/generations/{id} carries the reason a few seconds later'
'503':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: A dependency is unavailable; retry later
security:
- ApiKeyAuth: []
- SessionAuth: []
summary: Start a generation
tags:
- Generations
/api/v2/generations/estimate:
post:
description: Same body as POST /api/v2/generations. Runs the same checks, answering the same 400 errors, and returns the credit cost, your balance and whether it covers the cost, without starting anything or charging. Input images and videos are optional here, so a request can be priced before its files are uploaded.
operationId: estimateGeneration
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationRequest'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/GenerationEstimate'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Invalid request
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Missing or invalid credentials
security:
- ApiKeyAuth: []
- SessionAuth: []
summary: Price a generation
tags:
- Generations
/api/v2/generations/{id}:
get:
description: 'Status, cost and output files of one generation. Poll this until status is failed, or completed with a non-empty outputs array: the files are attached a moment after the status turns completed. Output URLs are unguessable links that work without authentication; anyone you share one with can download the file.'
operationId: getGeneration
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Generation'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Invalid request
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Missing or invalid credentials
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Not found
security:
- ApiKeyAuth: []
- SessionAuth: []
summary: Read a generation
tags:
- Generations
components:
schemas:
Generation:
properties:
cost:
description: 'Credits the generation costs: taken when it was accepted, less the share of any images it was asked for and did not deliver, which is refunded'
type: number
created:
format: date-time
type: string
error:
description: Why it failed, when it did
type: string
id:
type: string
input:
description: The request body as submitted
type: object
model:
type: string
outputs:
items:
$ref: '#/components/schemas/Output'
type: array
prompt_used:
description: The prompt the model was given, when translate_prompt or enhance_prompt rewrote the one in input
type: string
status:
enum:
- pending
- completed
- failed
- stalled
- canceled
type: string
type:
enum:
- image
- video
type: string
updated:
format: date-time
type: string
type: object
Output:
properties:
content_type:
type: string
filename:
type: string
id:
type: string
poster_url:
description: First frame of a video output as JPEG, an unguessable link like url; absent for images
format: uri
type: string
url:
description: Unguessable link that downloads without authentication; anyone holding it can fetch the file
format: uri
type: string
type: object
GenerationRequest:
description: 'model, plus the fields that model takes (GET /api/v2/models/{id}), enhance_prompt / translate_prompt, which every model with a prompt takes, and idempotency_key and callback_url, which every model takes. A field the model does not take, a missing required field or an invalid value answers 400 validation_failed, on the estimate as on the generation, except that the estimate does not require input images or videos, so a request can be priced before its files are uploaded. (A web-app session is lenient: it may estimate before the prompt exists, and its extra fields are ignored.)'
properties:
aspect_ratio:
description: Output aspect ratio
type: string
audio:
description: URL of an audio file (voice or music) the video syncs to
type: string
audio_setting:
description: 'Video editing: auto generates new audio, origin keeps the input video''s audio'
type: string
background:
description: Whether the background is transparent or opaque
type: string
callback_url:
description: 'Optional https URL, up to 2048 characters. When the job is final, completed with its outputs or failed or canceled with its error, it is POSTed there once, as JSON: the body GET /api/v2/generations/{id} answers. A network error, a 5xx or a 429 is retried for about six minutes; any other answer ends it. Nothing signs the request, so read the job back with GET before trusting what it says'
format: uri
maxLength: 2048
type: string
camera_fixed:
description: Keep the camera position fixed
type: boolean
character_orientation:
description: Character orientation source for motion control
type: string
duration:
description: Video duration in seconds
type: integer
enable_sequential:
description: 'Batch mode: generate a set of related images (up to 12)'
type: boolean
enhance_prompt:
description: Rewrite the prompt in more detail before generating, with the model's prompting guide or its own built-in rewriter (GET /api/v2/models/{id} says which); free, included in the generation price
type: boolean
first_clip_url:
description: URL of a video clip to continue (image-to-video mode); use instead of image and last_image
type: string
fps:
description: Frames per second
type: integer
generate_audio:
description: Generate a soundtrack for the video
type: boolean
go_fast:
description: Use faster generation mode
type: boolean
google_search:
description: Enable Google Search grounding for image generation
type: boolean
guidance:
description: Guidance scale (CFG scale)
type: number
guidance_scale:
description: Guidance scale (CFG scale)
type: number
height:
description: Output height in pixels
type: integer
high_performance:
description: Use high performance mode (better quality)
type: boolean
idempotency_key:
description: 'Any string you choose, up to 255 characters. A create repeated with the same key (after a timeout, say) returns the first job, marked idempotent_replay: true, instead of starting and charging a second; while the first is still being submitted the repeat answers 409 idempotency_in_progress. A different request under a used key answers 422 idempotency_key_reused, so use a new key for a new request'
maxLength: 255
type: string
image:
description: 'Input image URL: the image to edit, animate or work on'
type: string
image_input:
description: Multiple image URLs for editing or reference
items:
type: string
type: array
infer_steps:
description: Number of denoising steps
type: integer
input_image:
description: Input image URL
type: string
is_pro:
description: Use Pro variant
type: boolean
last_image:
description: URL of the image the video ends on; pair with image, which it starts on
type: string
lora_scale:
description: LoRA scale factor
type: number
lora_scale_transformer:
description: How strongly the transformer LoRA is applied
type: number
lora_scale_transformer_2:
description: How strongly the second transformer LoRA is applied
type: number
lora_weights:
description: LoRA weights URL or identifier
type: string
lora_weights_transformer:
description: URL of LoRA weights (.safetensors) for the transformer
type: string
lora_weights_transformer_2:
description: URL of a second set of LoRA weights (.safetensors) for the transformer
type: string
max_images:
description: Most images to make; state the same number in the prompt. The model may make fewer, and images not delivered are refunded
type: integer
megapixels:
description: Approximate output size in megapixels
type: string
model:
description: Model id from GET /api/v2/models
enum:
- flux-dev
- flux-kontext-pro
- gpt-image-2
- gpt-image-2.5
- hunyuan
- imagen-4-ultra
- kling-3.0
- kling-3.0-turbo
- motion-control
- nano-banana
- nano-banana-2
- nano-banana-2-lite
- nano-banana-2.1
- nano-banana-pro
- qwen-image
- qwen-image-2.1
- qwen-image-edit
- qwen-image-edit-plus
- qwen-image-edit-plus-lora
- qwen-image-layered
- recraft-crisp-upscale
- remove-background
- restore-image
- seedance-2
- seedance-2-mini
- seedance-2.5
- seedance-pro
- seedream-3
- seedream-4
- seedream-4.5
- seedream-5-flash
- seedream-5-lite
- seedream-5-pro
- veo2
- veo3
- veo3-fast
- veo3.1
- vidu-q4
- vidu-q4-reference
- wan-2.2
- wan-2.6
- wan-2.7
- wan-2.7-image
- wan-3.0
- wan-3.0-prime
type: string
n:
description: 'Number of images, billed per image: 1-4, or 1-12 with enable_sequential. 1 when omitted. Images not delivered are refunded'
type: integer
negative_prompt:
description: Negative prompt to avoid certain content
type: string
num_frames:
description: 'Clip length in frames: the clip lasts num_frames / fps seconds. 121 when omitted (5 s at 24 fps), or 81 with high_performance (3.4 s)'
type: integer
num_inference_steps:
description: Number of denoising steps
type: integer
num_layers:
description: Number of layers to split the image into, 2 to 8 (billed per layer)
type: integer
num_outputs:
description: Number of images to generate, billed per image; images not delivered are refunded
type: integer
optimize_prompt:
description: 'The model''s own option: it translates the prompt to Chinese before generating. Independent of translate_prompt, which translates the prompt to English before the model gets it; one of the two is enough for a prompt in another language'
type: boolean
output_format:
description: Output image format
type: string
output_quality:
description: Output quality (1-100)
type: integer
prompt:
description: The prompt to generate from
type: string
prompt_extend:
description: Let the model expand the prompt before generating
type: boolean
prompt_strength:
description: Strength of prompt influence for image-to-image
type: number
quality:
description: 'Quality level: basic (2K) or high (4K)'
type: string
reference_audios:
description: Audio URLs that steer the soundtrack (3 to 5 at most, by model); ignored when image or last_image is set
items:
type: string
type: array
resolution:
description: Output resolution
type: string
sample_shift:
description: 'Shifts the denoising schedule: higher values favour overall composition and motion, lower values fine detail'
type: number
seed:
description: Random seed for reproducibility; 0 or omitted picks one at random
type: integer
size:
description: Output size preset
type: string
thinking_mode:
description: Reason about the prompt before generating; text-to-image without enable_sequential only
type: boolean
translate_prompt:
description: Translate the prompt to English before generating; free, included in the generation price
type: boolean
veo31_generation_type:
description: 'How the images in veo31_image_urls are used. Leave it out and the count decides: no images is TEXT_2_VIDEO, one or two are the first and last frames (FIRST_AND_LAST_FRAMES_2_VIDEO), three are reference images (REFERENCE_2_VIDEO, which takes veo3_fast and 16:9 only)'
type: string
veo31_image_urls:
description: '1 to 3 image URLs: one image is the first frame, two are the first and last frames, three are reference images for the subject and style'
items:
type: string
type: array
veo31_model:
description: 'Quality tier: veo3 renders at higher quality, veo3_fast renders faster and costs less'
type: string
veo31_watermark:
description: Watermark text to put on the video
type: string
video_input:
description: Multiple video URLs for video-to-video generation
items:
type: string
type: array
video_length:
description: 'Clip length in frames: the clip lasts video_length / fps seconds, 129 frames at 24 fps (5.4 s) by default'
type: integer
watermark:
description: Add a watermark to the output
type: boolean
web_search:
description: Let the model look up the prompt's subject on the web; text-to-video only
type: boolean
width:
description: Output width in pixels
type: integer
required:
- model
type: object
GenerationList:
properties:
generations:
items:
$ref: '#/components/schemas/Generation'
type: array
next_cursor:
description: Opaque; pass it unchanged as cursor to fetch the next page. Absent on the last page
type: string
type: object
Error:
properties:
balance:
type: number
code:
type: string
cost:
type: number
error:
type: string
id:
description: The failed generation, on generation_failed
type: string
required:
- error
- code
type: object
GenerationEstimate:
properties:
affordable:
description: Whether balance covers cost
type: boolean
balance:
description: Your credits now
type: number
cost:
type: number
model:
type: string
shortfall:
description: Credits missing to cover cost; 0 when affordable
type: number
type:
enum:
- image
- video
type: string
variant:
type: string
type: object
GenerationAccepted:
properties:
cost:
type: number
id:
type: string
idempotent_replay:
description: 'true when an earlier idempotency_key answered with its job: cost was charged once, by the first request. Absent for a new job'
type: boolean
model:
type: string
status:
description: pending for a new job; a repeat with an earlier idempotency_key answers that job's current status
enum:
- pending
- completed
- failed
- stalled
- canceled
type: string
type:
enum:
- image
- video
type: string
type: object
securitySchemes:
ApiKeyAuth:
bearerFormat: sk-...
description: 'API key as `Authorization: Bearer sk-...`. The same secret is also accepted in an `X-API-Key` header, with or without the `Bearer ` prefix. Keys are created and deleted on the profile page; a key signs the routes in this document, can revoke itself at /api/oauth/revoke, and cannot create keys, delete other keys or change the account. It can start a checkout, which only a person paying by card completes.'
scheme: bearer
type: http
SessionAuth:
description: PocketBase session token, as issued to the web app.
in: header
name: Authorization
type: apiKey