Skip to content
API Reference · Image Generation API

Image Generation API

Asynchronous image generation, editing (image-to-image & mask), and variations - create, poll, retrieve. Persistent r2_url plus one-time b64_json within a 30-minute task TTL.


Overview

Every image operation is an asynchronous task: a POST returns a task ID immediately, then you poll GET /images/generations/{id} until status becomes completed. Three task families share that one polling endpoint:

  • Text-to-imagePOST /images/generations/async (prompt only)
  • Image editing (image-to-image & mask)POST /images/edits (source image + prompt, optional mask)
  • Image variationPOST /images/variations (source image only)

Editing and variation take an input image. The recommended path uploads that image to R2 first via POST /uploads/presign and submits the returned upload_id as JSON, so large image bytes never traverse the gateway. A legacy multipart/form-data path is kept for compatibility.

Call GET /images/models for the live model list. Full schema and constraints are available in the interactive API explorer.

EndpointPurpose
GET https://api.alltoken.ai/v1/images/modelsList available image models
POST https://api.alltoken.ai/v1/uploads/presignPresign an R2 upload for an input image / mask
POST https://api.alltoken.ai/v1/images/generations/asyncCreate a text-to-image task
POST https://api.alltoken.ai/v1/images/editsCreate an image edit task (i_edit / mask_edit)
POST https://api.alltoken.ai/v1/images/variationsCreate an image variation task
GET https://api.alltoken.ai/v1/images/generations/{id}Poll task status / retrieve result

Prefer r2_url over b64_json: a completed response returns both, but b64_json is deprecated and delivered only on the first read (the temporary file is deleted right after). r2_url is a public URL that stays valid for at least 30 days and survives re-polls. Tasks themselves expire after 30 minutes.

List Image Models

GET
$GET https://api.alltoken.ai/v1/images/models

Returns all available image generation models in OpenAI-compatible format.

Response JSON
1{
2 "object": "list",
3 "data": [
4 { "id": "gpt-image-2", "object": "model", "owned_by": "openai" }
5 ]
6}

Create an Image Generation Task

POST
$POST https://api.alltoken.ai/v1/images/generations/async

Headers:

  • Authorization: Bearer <API_KEY> - required
  • Idempotency-Key: <uuid> - optional but recommended. Server dedupes within a short window; retries with the same key return the original task.
Request body JSON
1{
2 "model": "gpt-image-2",
3 "prompt": "A clean product photo of a glass teapot on a walnut table, soft natural light",
4 "size": "1024x1024",
5 "quality": "high",
6 "output_format": "png",
7 "background": "auto",
8 "moderation": "auto"
9}

Response (task created, status queued):

Response JSON
1{
2 "id": "igen_a7b68c38c4b7832ee386a13e",
3 "status": "queued",
4 "model": "gpt-image-2",
5 "created_at": "2026-05-12T08:00:00Z"
6}

Request Parameters

These apply to the POST /images/generations/async body. Image editing (/images/edits) accepts the same n / size / quality / output_format / output_compression / background / moderation fields.

  • model (required) - Image model ID. Text-to-image accepts gpt-image-2, wan2.7-image, or wan2.7-image-pro; call GET /images/models for the live list
  • prompt (required) - Text description of the desired image (max 32000 characters)
  • n - Number of images to generate, 1-10 (default 1)
  • size - auto or WIDTHxHEIGHT. From gpt-image-2 on, arbitrary resolutions are supported (each side a multiple of 16, max 3840x2160, aspect ratio between 1:3 and 3:1), e.g. 1024x1024 / 1536x1024 / 1024x1536
  • quality - low / medium / high / auto; controls inference budget and per-image cost
  • output_format - png / jpeg / webp
  • output_compression - 0-100, applies to jpeg / webp only (upstream defaults to 100)
  • background - auto / opaque / transparent
  • moderation - auto (default; recommended) / low (less restrictive; user accepts full content compliance responsibility)

Uploading Input Images

Image editing and variation need a source image (and optionally a mask). The recommended flow uploads each file straight to R2 with a presigned URL, then submits its upload_id — keeping large bytes off the gateway and the Cloudflare edge.

Step 1 — request a presigned URL:

POST
$POST https://api.alltoken.ai/v1/uploads/presign
Request body JSON
1{
2 "purpose": "image_edit_source",
3 "content_type": "image/png",
4 "content_length": 524288,
5 "content_md5": "1B2M2Y8AsgTpgAmY7PhCfg==",
6 "checksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
7}
  • purpose (required) - image_edit_source, image_edit_mask, or image_variation_source. The purpose is re-validated when you submit the task; uploads cannot be reused across purposes
  • content_type (required) - image/png / image/jpeg / image/webp (must match the purpose allowlist; the server re-checks the real type on bind)
  • content_length (required) - Byte length; each purpose has its own cap (echoed back as max_content_length)
  • content_md5 (required) - Base64 MD5; you must send the same value as Content-MD5 on the R2 PUT
  • checksum_sha256 (required) - Lowercase hex SHA-256, used for the server-side consistency check on bind
Response JSON
1{
2 "upload_url": "https://r2.alltoken.ai/inputs/upl_2f8bb7d7f4a24c3a8f4f8a7e?signature=...",
3 "method": "PUT",
4 "required_headers": {
5 "Content-Type": "image/png",
6 "Content-MD5": "1B2M2Y8AsgTpgAmY7PhCfg=="
7 },
8 "upload_id": "upl_2f8bb7d7f4a24c3a8f4f8a7e",
9 "expires_in": 300,
10 "claim_expires_at": "2026-05-15T05:00:00Z",
11 "max_content_length": 26214400
12}

Step 2 — PUT the file to R2 at upload_url with the exact required_headers. The presigned URL is valid for expires_in seconds (currently 300):

cURL
$curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/png" \
  -H "Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==" \
  --data-binary @teapot.png

Step 3 — submit the upload_id to /images/edits or /images/variations (below). An unclaimed upload is deleted ~2 hours after presign; a bound input is deleted as soon as the task succeeds, fails, or is cancelled. Submit only upload_id — the debug-only public_url is not accepted as task input.

Edit an Image (image-to-image & mask)

Create an image-to-image task from a required source image plus a prompt. Omit mask for a whole-image edit (i_edit); include a mask to edit only the masked region (mask_edit) — the mask's transparent pixels mark the editable area.

POST
$POST https://api.alltoken.ai/v1/images/edits

Recommended — JSON with uploaded inputs (presign the source/mask first, see above):

Request body JSON (application/json)
1{
2 "model": "gpt-image-2",
3 "prompt": "Replace the sky with a dramatic sunset",
4 "image_upload_id": "upl_2f8bb7d7f4a24c3a8f4f8a7e",
5 "mask_upload_id": "upl_9c1aa0e2b7d3490f8e2c1a55",
6 "size": "1024x1024",
7 "quality": "high",
8 "output_format": "png"
9}
  • model (required) - e.g. gpt-image-2
  • prompt (required) - Edit instruction (max 32000 characters)
  • image_upload_id (required) - upload_id from a purpose=image_edit_source presign
  • mask_upload_id - Optional; upload_id from a purpose=image_edit_mask presign. Its presence switches the task to mask_edit
  • n - Number of images, 1-10 (default 1)
  • size, quality, output_format, output_compression, background, moderation - Same as text-to-image (see Request Parameters)

Legacy — multipart/form-data (kept for compatibility; large bodies may hit 413 / edge challenges). Send model, prompt, a binary image field, and an optional binary mask field. The source image and mask are each ≤ 25MB, MIME image/png / image/jpeg / image/webp.

Response (202, task created) - the task ID is prefixed igen_iedit_ (i_edit) or igen_mask_ (mask_edit); poll it on GET /images/generations/{id}:

Response JSON
1{
2 "id": "igen_iedit_a7b68c38c4b7832ee386a13e",
3 "status": "queued",
4 "model": "gpt-image-2",
5 "created_at": "2026-05-15T03:00:00Z"
6}

Image Variations

Create variations of a required source image. No prompt or mask is accepted. Variations only work on models that support them (e.g. dall-e-2); unsupported models return an upstream 4xx passed through the gateway.

POST
$POST https://api.alltoken.ai/v1/images/variations
Request body JSON (application/json)
1{
2 "model": "dall-e-2",
3 "image_upload_id": "upl_2f8bb7d7f4a24c3a8f4f8a7e",
4 "size": "1024x1024"
5}
  • model (required) - A variation-capable model, e.g. dall-e-2
  • image_upload_id (required) - upload_id from a purpose=image_variation_source presign
  • size - auto / 1024x1024 / 1536x1024 / 1024x1536

The legacy multipart/form-data path sends a binary image field (≤ 25MB) instead of image_upload_id. The returned task ID is prefixed igen_ivar_; poll it on GET /images/generations/{id}.

Get Task Status

GET
$GET https://api.alltoken.ai/v1/images/generations/{id}

Returns task details. This single endpoint serves every task family (text-to-image, edits, variations). When status is completed, the data array carries each generated image as a persistent r2_url plus a one-time b64_json (base64-encoded PNG/JPEG/WebP per the requested output_format).

Response JSON (completed)
1{
2 "id": "igen_a7b68c38c4b7832ee386a13e",
3 "status": "completed",
4 "model": "gpt-image-2",
5 "created": 1778572818,
6 "completed_at": "2026-05-12T08:00:18Z",
7 "expires_at": "2026-05-12T08:30:18Z",
8 "size": "1024x1024",
9 "quality": "high",
10 "output_format": "png",
11 "data": [
12 {
13 "r2_url": "https://r2.alltoken.ai/images/igen_a7b68c38.png",
14 "r2_url_expires_at": "2026-06-11T08:00:18Z",
15 "mime_type": "image/png",
16 "b64_json": "iVBORw0KGgo...",
17 "revised_prompt": "A clean studio product photo of a clear borosilicate glass teapot..."
18 }
19 ],
20 "usage": {
21 "input_tokens": 24,
22 "output_tokens": 1290,
23 "total_tokens": 1314
24 }
25}

Prefer r2_url; b64_json is one-time: the first completed read returns both, but b64_json is deprecated and the temporary file is deleted right after. r2_url is a public URL valid for at least 30 days (until r2_url_expires_at) and is returned on every subsequent read. If R2 upload failed there is no r2_url — keep the first b64_json; re-reading with no R2 fallback returns 410 image_already_retrieved, and an expired r2_url returns 410 image_expired.

Task Status Values

  • queued - Enqueued, waiting for GPU
  • processing - Model is generating
  • completed - Done; data[].b64_json available for one read
  • failed - Generation failed; details in error
  • cancelled - Cancelled before completion

Recommended polling interval: 1-3 seconds. Most tasks complete in 8-25 seconds; high-quality 1536x1024 jobs may take 30-60 seconds. Expired or already-retrieved results are returned as 410 errors.

Error Responses

  • 400 - Bad request, such as an empty prompt or invalid size
  • 401 - Invalid or missing API Key
  • 402 - Insufficient API usage quota
  • 404 - Task ID not found
  • 409 - Duplicate Idempotency-Key for an already-active task, or another request is currently claiming the completed result
  • 410 - Task expired (30-minute TTL elapsed) or result was already retrieved
  • 413 - Uploaded file too large (source image or mask > 25MB on the multipart path)
  • 429 - Rate limit exceeded; respect the Retry-After header
  • 503 - Gateway R2 storage is not configured, or upstream storage is unavailable