---
title: Batch Image Generation API: Budget-Safe Pipeline
description: "Batch image generation API done safely: durable queues, idempotency, bounded concurrency, 500-SKU cost math and key-level spending limits."
url: https://apitoken.sale/docs/learn/batch-image-generation-api
language: en
---

# Build a batch image generation pipeline that cannot overrun its budget

There is no batch endpoint to call. On both published image routes, one admitted request returns exactly one candidate image, so a production batch pipeline is your own durable queue in front of Nano Banana 2 (gemini-3.1-flash-image) or GPT Image 2 — with bounded workers, per-asset attempt budgets, terminal-usage reconciliation and a key-level lifetime spending limit as the final monetary boundary.

## One admitted call returns one candidate

Neither public image route accepts a count, a manifest or a folder of prompts. A Gemini generateContent call on gemini-3.1-flash-image returns one candidate whose image travels as base64 in inlineData; an OpenAI-compatible POST /v1/images/generations on gpt-image-2 returns a single-element data array with b64_json. The model never sees "make 500 variations" — batch size is a property of your queue, not of the request.

```
// gemini-3.1-flash-image → one candidate, image as base64 inlineData
{
  "candidates": [
    { "content": { "parts": [ { "inlineData": { "mimeType": "image/png", "data": "<base64>" } } ] } }
  ],
  "usageMetadata": { "promptTokenCount": 24, "candidatesTokenCount": 1120, "totalTokenCount": 1144 }
}

// gpt-image-2 → single-element data array, image as b64_json
{
  "created": 1754800000,
  "data": [ { "b64_json": "<base64>" } ],
  "usage": { "input_tokens": 38, "output_tokens": 4096, "total_tokens": 4134 }
}
```

Plan storage for both shapes at design time: decode the base64 payload once, checksum the bytes and persist them beside the job. A URL-shaped output, when a route returns one, is a fetch task with its own expiry — not a durable asset.

## One durable job per asset, not per prompt

1. Create a stable asset ID and an immutable brief — prompt, references, protected traits — before anything is enqueued.
2. Resolve the model, protocol, output size and maximum attempts into the job payload, so a retry replays the same decision rather than making a new one.
3. Give each worker a bounded slice of the queue and reserve one provider request per candidate; never ask the model for an internal batch.
4. Persist the request ID, terminal usage, output checksum and validation verdict atomically with the asset version.
5. Mark the job complete only after storage and downstream publication both confirm the same asset version.

```
{
  "asset_id": "catalog/sku-1042/hero-v3",
  "idempotency_key": "sku-1042:hero-v3:attempt-1",
  "model": "gemini-3.1-flash-image",
  "size": "1K",
  "max_attempts": 2,
  "spending_key": "image-production"
}
```

## Cost math for a 500-SKU run

Nano Banana 2 publishes fixed image-output legs: 1K is 1,120 image tokens, $0.0672 officially and $0.0336 for a regular B2C account; after the same 50% policy, 2K is $0.0504 and 4K is $0.0756. GPT Image 2 has no honest per-picture constant: its image output bills at $15 per 1M tokens for regular B2C, and the settled total follows terminal usage. Work the example with the fixed leg, because that is the only part you can know before the run.

| Line | Value |
| --- | --- |
| Assets in the campaign | 500 SKUs |
| Candidates per asset | 2 |
| Admitted calls | 1,000 |
| Image output per 1K candidate (regular B2C) | $0.0336 |
| Base image-output spend | 1,000 × $0.0336 = $33.60 |
| Retry budget: 10% of assets, one extra attempt | +$3.36 |
| Worst-case image-output spend | $36.96 |

> This is the image-output leg only. Text and image input, optional text or thinking output, and grounding are added from terminal usage. The 50% B2C discount halves official usage; it does not cap the product of assets × candidates × retries × resolution — that product is yours to bound.

[The per-leg token rates behind this batch math](/docs/learn/image-generation-api-pricing)

## Bound every multiplier, not just the price

| Multiplier | Guardrail |
| --- | --- |
| Assets | Explicit queue length and campaign budget |
| Variants | Maximum candidates per asset |
| Retries | Only proven not-started attempts; total deadline |
| Resolution | Default 1K; promote by delivery rule |
| References | Only files required by the brief |
| Concurrency | Small worker ceiling with 429 cooling |

> A key's lifetime spending limit is the last monetary boundary when every application-level guardrail fails. Set it to the campaign budget plus a measured safety margin — not to the account balance.

## Retry, cooling and observability rules

- Never retry after image bytes or a complete provider response were delivered — that retry is a second paid candidate, not a recovery.
- Treat an ambiguous timeout as reconciliation work: match the request ID against the dashboard charge before concluding that no billable generation happened.
- Honor 429 responses with Retry-After, provider cooling and jitter inside a total deadline; immediate fan-out amplifies a capacity event.
- Track attempts, accepted assets, settled nanoUSD and validation failure reasons; keep prompts and keys out of metrics.
- Alert on cost per accepted asset and failure share, not only on HTTP success rate — a fully green batch can still be an expensive one.

> Settled cost per accepted asset is the batch's real unit economics: it folds token price, resolution, retries and quality rejects into the single number the business actually buys.

## Isolate the batch lane with its own key and budget

Run the batch worker on a dedicated key with a lifetime spending limit and an expiration date, so a queue bug can exhaust only the campaign budget, never the account. A new account created with Google or GitHub starts with $5 of platform bonus credit — enough to validate the pipeline end to end before the first top-up; after that, fund any whole-dollar amount by bank card or cryptocurrency such as USDT or BTC. The prepaid balance never expires, and there is no subscription to size.

- One key per workload: batch generation never shares a key with interactive or editing traffic.
- Reconcile every settled charge against its request ID before the campaign is closed.
- Re-check the lifetime spending limit before each new campaign, not once at setup.

[Prepaid plans that never expire: fund exactly the campaign budget](/plans)

## Frequently asked questions

### Can one API request generate a whole batch of images?

No, on the published routes. One admitted call returns one candidate image; there is no count parameter that multiplies it. Batch size, ordering and concurrency belong to your durable queue — which is also where budgets are enforced before any money moves.

### How much would a 1,000-image batch cost?

On Nano Banana 2 at 1K, the fixed image-output leg is 1,120 tokens per candidate — $0.0336 for regular B2C — so 1,000 candidates cost $33.60 of image output, plus input and optional grounding legs from terminal usage. GPT Image 2 bills image output at $15 per 1M tokens for regular B2C with no fixed per-image constant, so its batch total is known only from settled usage.

### How do I stop a runaway image batch?

Combine a dedicated key carrying a lifetime spending limit, an explicit queue length, bounded workers, a per-asset maximum attempt count and a total campaign budget. Each layer fails independently, and the key-level limit is the boundary that holds even if all the others misbehave.

### Should 429 responses be retried immediately?

No. Respect Retry-After and provider cooling, add jitter and keep a total deadline per job. Immediate fan-out during a capacity event converts a slowdown into an outage you paid to create.

### Should the pipeline store the base64 payload or a URL?

Treat the API response as transport, not storage. Decode base64 once, checksum and persist the bytes in your own object storage, then publish optimized WebP/AVIF derivatives; never serve the raw API payload as a storefront asset.

### Does the 50% discount apply to every call in a batch?

For regular B2C accounts it applies to the official usage of every admitted call, generation or edit. B2B accounts follow their negotiated policy, and OpenKeys bill 1:1 at official prices. A discount never proves that a model is currently available to a particular key.

---
Get a key: https://apitoken.sale/register
More guides: https://apitoken.sale/docs/learn
