Knowledge base

Tìm nhanh trong tài liệu Zora

Image Generation

Generate images through the Zora public API with gpt-img-2. Each accepted request creates one image. Use async image jobs when the client wants a quick submit response and a polling URL; use the OpenAI-compatible route only when the client is willing to wait for one image.

One image per request
Zora no longer accepts server-side image batches. n must be 1. To generate 50 images, submit 50 independent one-image jobs and poll each job separately. Render each image as soon as its own job returns completed; do not wait for the other jobs.
Image-only plan limits
Image-only keys use a rolling RPM window. A 15 RPM image key can submit up to 15 one-image requests immediately; each used slot becomes available again 60 seconds after it was accepted. If 1 image was accepted less than 60 seconds ago, only 14 more image requests can be accepted until that slot refills.
No over-RPM queue
The server does not queue image requests that exceed the key's RPM. Requests over the rolling window return HTTP 429 with Retry-After. Submit again after the indicated delay.

Endpoints

HTTP
POST https://api.zora.io.vn/v1/images/jobs GET https://api.zora.io.vn/v1/images/jobs/{job_id} POST https://api.zora.io.vn/v1/images/generations # n=1 only

Async Image Job

This is the recommended production path. Submit returns quickly with 202, then the client polls the returned status URL until the one image reaches a terminal state.

curl
curl https://api.zora.io.vn/v1/images/jobs \ -H "Authorization: Bearer YOUR_ZORA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: customer-image-20260619-001" \ -d '{ "model": "gpt-img-2", "prompt": "Create a funny motion sticker", "n": 1, "size": "1024x1024", "response_format": "url", "upload_to_storage": true }'
JSON
{ "id": "imgjob_...", "status": "queued", "status_url": "/v1/images/jobs/imgjob_...", "poll_after_seconds": 5, "requested": 1, "succeeded": 0, "failed": 0, "pending": 1 }
curl
curl https://api.zora.io.vn/v1/images/jobs/imgjob_... \ -H "Authorization: Bearer YOUR_ZORA_API_KEY"
JSON
{ "id": "imgjob_...", "status": "generating", "requested": 1, "succeeded": 0, "failed": 0, "pending": 1, "progress": { "completed": 0, "total": 1, "percent": 0 }, "data": [], "items": [ { "index": 1, "status": "running", "attempts": 1 } ], "poll_after_seconds": 5 }

Recommended loop: submit one image request per desired output, poll each accepted job independently every 5-10 seconds, and respect Retry-After on both job polling and HTTP429 rate limit responses.

Progressive rendering
Client applications should update their gallery from each job's latest data or completed items on every poll. Each job tracks exactly one image, so a slow retry only delays that one job.

Different Prompts

Submit one job per desired image. items is accepted only with one item, so it is mainly a compatibility shape for clients that already build item payloads.

curl
curl https://api.zora.io.vn/v1/images/jobs \ -H "Authorization: Bearer YOUR_ZORA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: gallery-item-001" \ -d '{ "model": "gpt-img-2", "size": "1152x2048", "response_format": "url", "upload_to_storage": true, "items": [ { "prompt": "other angle", "image_url": "https://example.com/input-1.jpg" } ] }'

Synchronous One-Off

Use this route only for convenience calls where the client is willing to wait for one image. Requests with n higher than 1 are rejected.

curl
curl https://api.zora.io.vn/v1/images/generations \ -H "Authorization: Bearer YOUR_ZORA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-img-2", "prompt": "A clean product photo of a ceramic coffee cup", "n": 1, "size": "1024x1024", "response_format": "url", "upload_to_storage": true }'

Successful URL responses are normalized to Zora-hosted public download links underhttps://api.zora.io.vn/v1/images/files/.... The files are backed by Cloudflare R2 when storage is available, with a local Zora cache as fallback.

Response

JSON
{ "created": 1780656950, "data": [ { "url": "https://api.zora.io.vn/v1/images/files/generated-1781867780-ecbcabe4d092.png", "raw_url": "https://api.zora.io.vn/v1/images/files/generated-1781867780-ecbcabe4d092.png", "filename": "generated-1781867780-ecbcabe4d092.png", "source": "cloudflare_r2" } ], "requested": 1, "succeeded": 1, "failed": 0 }

Image To Image

Send a public HTTPS image URL or a data:image/...;base64,... data URI through image_url, input_image, or image. Each input image can be up to 10 MB. Very large phone photos are automatically resized when they exceed 20 megapixels. Use size: "auto" when you want Zora to preserve or infer the canvas/aspect ratio.

curl
curl https://api.zora.io.vn/v1/images/generations \ -H "Authorization: Bearer YOUR_ZORA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-img-2", "prompt": "Turn this product photo into a premium studio ad, keep the object shape", "image_url": "https://example.com/reference.png", "n": 1, "size": "auto", "response_format": "url", "upload_to_storage": true }'

Multiple Reference Images

To send several uploaded images, pass an array in image_url, input_image, or image. The current limit is 4 reference images per request.

JSON
{ "model": "gpt-img-2", "prompt": "Design a banner using the logo and product reference", "image_url": [ "https://example.com/logo.png", "https://example.com/product-photo.jpg" ], "n": 1, "size": "auto", "response_format": "url", "upload_to_storage": true }

Request Fields

FieldValue
modelgpt-img-2
promptRequired text instruction.
n1 only. Each accepted request costs 1 image and 1 rolling-RPM slot.
size1024x1024 by default. Use a fixed value such as 1024x1024, 1024x1536, or 1536x1024 when outputs must have consistent pixel dimensions. Use auto only when variable canvas/aspect ratio is desired.
response_formaturl or b64_json.
upload_to_storageCompatibility flag. URL responses are returned as Zora-hosted public files when possible.
image_urlOptional string or array of up to 4 public HTTPS URLs or base64 data URIs.
itemsOptional array with exactly 1 per-image payload. More than 1 item returns HTTP 400.

Operational Notes

  • Image-only keys are scoped to image routes; do not smoke test them with GET /v1/models.
  • Use /v1/images/jobs for UIs that want quick submit responses and polling.
  • Submit one image per request. Requests above rolling RPM return HTTP 429; they are not queued.
  • Render completed job items immediately.
  • Poll each active job using the response Retry-After header or poll_after_seconds. Do not poll every card every second.
  • For uniform gallery cards, send an explicit fixed size. Fixed-size outputs are normalized to that canvas; size: "auto" can return mixed dimensions.
  • Use /v1/images/generations only for one-off n: 1 convenience calls.
  • The daily bucket is UTC. There is no fixed monthly total cap beyond the active 30-day validity and daily quota.
  • If an image job fails, retry it with a new idempotency key after checking the current RPM window.