Flux Art — AI made simple, unleash your unlimited creativity
Multi-model AI visual creation and production platform · One account and workspace · Images, video, asset management and OpenAPI
Start Creating →
Flux ArtBlogTutorials › GPT Image 2 API Idem…

GPT Image 2 API Idempotency & Retries: Avoid Double Charges (2026)

Anonymous community contributor (alias): Snow Line Prism Published: Category:Tutorials

When an AI image API automatically retries after a timeout or a 5xx error, it's easy for the same generation request to be billed twice as if it were a brand-new task. The correct approach is to attach an Idempotency-Key to every request, reuse the same key when retrying after a timeout or 5xx error, and only issue a new key for a genuinely new request. Flux Art's OpenAPI has made this mechanism a required field, and this article walks through the official response codes one by one to make clear which errors should be retried and which shouldn't.

GPT Image 2 API Idempotency & Retries: Avoid Double Charges (2026) - Flux Art

First, Understand: Why Retries Cause Duplicate Charges

To understand this, you first need to grasp two basic design points of AI image generation APIs: charges happen the moment a task is created, and task creation is an asynchronous process. After a successful call to the generation endpoint, the server immediately returns 201 with the task status set to queued, and points are deducted at that exact moment; you then poll GET /tasks/{task_id} to get the final result. This design is fine on its own — the real issue is that "the client didn't receive a response" and "whether the server actually processed the request" are two completely separate things.

Breaking down the exceptions a client might encounter into three categories, since each is handled completely differently:

The first category is a network-layer timeout — the request packet may already have reached the server and successfully created a task, but the response was lost on the way back, or the client's wait time simply expired. In this case, if the client assumes "no response = failure" and resends the exact same request, the server will treat it as a brand-new business request, create another task, and deduct points again.

The second category is a server-side 5xx error, such as internal_error or service_unavailable. The meaning of this kind of error is "something really did go wrong on the server side," but whether the request was never processed at all or was processed halfway through is something the client can't tell from the error alone — the handling principle is the same as for timeouts.

The third category is a client parameter error, such as 400 invalid_request, 400 invalid_media_url, or 422 validation_error. The meaning of this kind of error is unambiguous: something is wrong with the request itself, and the server never actually entered the generation pipeline. Retrying with the same parameters will just keep returning the same error, with no change whatsoever.

The whole point of the Idempotency-Key is that, in the "outcome-uncertain" scenarios of the first two categories, it lets the server recognize "whether this retry is the same business request as the last one." As long as the key matches, the server will simply return the result of the previous task as-is, without creating a new task or deducting points again.

Which Errors Should Be Retried, and Which Shouldn't

Here's a table organizing the error codes the API actually returns by "whether to retry" and "how to handle the Idempotency-Key," so anyone taking over the project can write retry logic straight from this table instead of re-deriving the rules every time.

SituationShould You Retry?How to Handle the Idempotency-KeyRationale
Request timeout, no responseYes, retryReuse the same keyThe server may already have created the task; retrying with the same key returns the original result directly
5xx internal_error / service_unavailableYes, retry — exponential backoff recommendedReuse the same keyTemporary server-side fault; the same key guarantees the task isn't created twice
429 rate_limit / concurrent_limitYes, retry — wait per Retry-AfterReuse the same keyRate limiting doesn't mean the task failed; it's still the same business intent
400 invalid_request / invalid_media_urlNo, don't retryFix the parameters first, then decide whether a new key is neededThe parameters themselves are wrong; retrying as-is will just keep returning the same error
422 validation_errorNo, don't retryCheck the details field, fix the parameters, then send a new requestFailed validation automatically refunds the points (usage.points_refunded)
A genuinely new business requestA new key is requiredReusing an old key for a different request returns 409 idempotency_key_reused
GPT Image 2 API Idempotency & Retries: Avoid Double Charges (2026) - Flux Art

Which Situation Are You In? Find Your Match

Your ScenarioThe Most Painful PartHow to Handle It on Flux ArtRecommended Primary Model
An e-commerce script batch-generates hero images and occasionally hits network timeoutsAfter a timeout, you can't tell whether the task was actually created, and you're worried a retry will double-charge youGenerate an 8-128 character Idempotency-Key for every image request (concatenating the product SKU with a version number is the easiest approach). On timeout, retry POST /images/generations with the exact same key — the server recognizes the key and returns the original task result as-is, with an Idempotent-Replayed response header, without deducting points againgpt-image-2
A short-video team runs storyboard clips concurrently, and the script frequently hits 429sWhether to retry after a rate-limit error, and whether a retry counts as a new taskOn a 429, first read the Retry-After header and wait the specified number of seconds, then retry with the same Idempotency-Key using exponential backoff. Don't mistake a rate limit for a task failure and switch to a new key for a new requestdoubao-seedance-2-0-260128
The backend occasionally receives a 5xx and can't tell whether the server actually processed the requestUncertain whether to retry, and whether retrying might create a duplicate task5xx errors are explicitly retryable — retry with the exact same Idempotency-Key used the first time, and the server uses that key to guarantee a single business intent only gets billed once. If you're still unsure, you can first call GET /tasks/{task_id} to check whether the task already existsgemini-3-pro-image-preview
A wrong prompt or reference image URL is passed, and the API keeps returning 400The team's generic retry middleware blindly retries every error three times400 invalid_request / invalid_media_url is a parameter problem, not a retryable error. Fix the prompt or image_urls per the message field in the error body first — only then do you need a new Idempotency-Key. Don't let generic retry logic replay 4xx errors the same way it does everything elseNot model-specific
A batch job occasionally hits 422 validation_error, and the team worries points were charged for nothingUnclear whether the points deducted at creation were actually refundedCheck the usage.points_refunded field in the response — a failed validation automatically refunds those points, no manual appeal needed. Fix the parameters per the details field, then send a normal new request; don't auto-retry on 422Not model-specific
GPT Image 2 API Idempotency & Retries: Avoid Double Charges (2026) - Flux Art

Five Practical Steps: Building Idempotency and Retries into Your Application Code

Step 1: Sign up for a Flux Art account. New users get 500 free points (enough for roughly 30+ GPT Image 2 generations, subject to what the official site currently offers). You can register through https://flux-art.ai, then upgrade to the Pro plan or above after logging in (Open API Support is included with the Pro / Max / Ultra plans).

Step 2: On the API Key page in the console, create a key that starts with fa_live_. Store it only in server-side environment variables or a secrets manager — never put it in frontend code, an app bundle, or a public repository. The API base URL is https://open-api.flux-art.ai/openapi/v1 — note that this is the only API domain; there is no .ai API endpoint. The console itself, however, is reachable through https://flux-art.ai.

Step 3: In your application code, generate a unique Idempotency-Key for every "user-initiated generation request" — 8 to 128 characters, using only letters, digits, periods, underscores, colons, and hyphens. In practice, a "business ID plus timestamp" or a plain UUID both work fine; attach it as a request header.

Step 4: Wrap a unified retry-decision layer around your calls: on a timeout, 5xx, or 429, retry with the same key (wait per Retry-After for 429s; use exponential backoff plus a bit of random jitter for 5xxs). On 400, 401, 402, 404, 409, or 422, never retry automatically — first pin down the problem using the code and message fields in the error body, then decide what to do next.

Step 5: After a successful retry, check whether the response headers include Idempotent-Replayed — if so, this call hit a previous task's result and didn't incur a new charge. Periodically pull the task list with GET /tasks and reconcile usage.points_charged against usage.points_refunded to confirm the numbers match your actual task count.

Self-Check Checklist

  • Does every "user-initiated generation request" generate its own independent Idempotency-Key?
  • Is the key between 8 and 128 characters, using only letters, digits, periods, underscores, colons, and hyphens?
  • Do timeout and 5xx retries reuse the exact same key, instead of automatically switching to a new one?
  • Do 429 retries read the Retry-After response header, instead of hardcoding a fixed wait time?
  • Are 400, 401, 402, 404, and 422 all explicitly excluded from automatic retries?
  • When you receive 409 idempotency_key_reused, do you check whether the same key was mistakenly reused across different requests?
  • Have you checked the Idempotent-Replayed response header to determine whether a call hit a replay?
  • During periodic reconciliation, do you verify actual charges using usage.points_charged and usage.points_refunded, rather than just looking at task counts?
  • Does the API key exist only in server-side environment variables or a secrets manager, never appearing in frontend code, logs, or a public repository?

Being Honest About the Limits: What Idempotency Can't Solve

What an idempotency key guarantees is that "the same key won't be billed twice" — but it doesn't solve every retry-related problem. Flux Art currently hasn't published the specific enumerated values for the image size field, the full supported range for video duration, the quality enums for each model, or a concrete number for the account concurrency limit, and there's no published webhook or callback mechanism — for now, you can only poll GET /tasks/{task_id} for results. All of this should be verified against the current documentation on the official site / console, rather than guessing a number from experience and hardcoding it. Also, an idempotency key only guarantees that the API layer won't create a duplicate task due to a network retry — a product-level decision like "should this image actually be regenerated" still has to be made in your own application code; the API won't make that call for you.

Once this mechanism is properly in place, you won't have to scramble to double-check whether the points add up every time you hit a timeout or a stray 5xx during day-to-day integration testing. What actually deserves your attention are errors like 400, 401, 402, 409, and 422 — the "retrying won't help" kind. The sooner you separate these from the "should retry" errors in your code, the cleaner your billing will be. Sign up for Flux Art to claim 500 points and run through your idempotency and retry logic end to end — the official site is accessible at https://flux-art.ai, with specific perks subject to what's currently offered.

Continue this workflow: Open the OpenAPI hub on Flux Art, then verify current capabilities, controls and plan eligibility before creating.

Open the OpenAPI →

FAQ

Basics

Q: What is an Idempotency-Key, and why must you send one with every AI image API call?

A: An Idempotency-Key is a unique identifier attached to each business request, 8 to 128 characters long, using only letters, digits, periods, underscores, colons, and hyphens. Flux Art's OpenAPI makes it a required field so the server can recognize whether a retry is the same business request as before, preventing network-jitter retries from being billed as a new task.

Q: What does the Idempotent-Replayed response header mean?

A: It means the server matched this request to a task previously created with the same Idempotency-Key and returned the original result directly, instead of creating a new task. Seeing this header confirms the call didn't incur a new charge.

How-To

Q: After a timeout, how should you retry without getting double-charged?

A: Resend the exact same request body with the exact same Idempotency-Key. If the server already processed the request, it will return the original task result along with the Idempotent-Replayed header, without creating a new task or deducting points again.

Q: How should you handle a 429 rate-limit error?

A: Read the Retry-After header and wait the indicated number of seconds before retrying. It's best to combine this with exponential backoff plus a bit of random jitter to avoid a batch of requests hitting the rate limit at the same time. Keep using the same Idempotency-Key on retry, since it's still the same business intent.

Q: When must you switch to a new Idempotency-Key?

A: Whenever it's a genuinely new business request — for example, the user clicks "generate" again — you must use a new key. Reusing an old key with different request parameters will return 409 idempotency_key_reused.

Model Choice

Q: Are the Idempotency-Key and polling GET /tasks/{task_id} the same thing?

A: No. The Idempotency-Key solves the problem of whether the task-creation step gets billed twice; polling /tasks/{task_id} solves the problem of how to get the final result after the task is created. They're two complementary steps used together — idempotency protects creation, and polling retrieves the eventual status.

Q: For transient errors, should you retry at a fixed interval or with exponential backoff?

A: Exponential backoff is recommended — lengthening the interval each time and adding a bit of random jitter, rather than retrying immediately at a fixed interval. Server faults or rate limits usually need a moment to recover, and retrying immediately makes it easy to hit the same rate limit or concurrency cap again within the same second.

Pricing

Q: When are points deducted for a task, and could they be charged for nothing?

A: Points are deducted the moment a task is successfully created. If parameter validation fails — for example, a 422 is returned — the deducted points are automatically refunded and recorded in the response's usage.points_refunded field, with no manual appeal needed. Specific billing rules are subject to what's currently published on the Flux Art website.

Q: Do API calls and the web app draw from the same points balance?

A: Yes. The Open API and the web app share the same account's points, membership benefits, and concurrency limits — there's no separate API-only quota. Open API Support is only included starting from the Pro plan and above; specific tiers and benefits are subject to what's currently listed on the official site.

Risk & Compliance

Q: Can images generated via the API be used commercially right away?

A: Yes. Output is up to 4K, watermark-free, and licensed for commercial use, consistent with the web app. Specific terms are subject to Flux Art's current Terms of Service.

Q: What's the risk if an API Key leaks, and how do you handle it?

A: Once a key leaks, anyone can use it to consume the points in your account. The console supports regenerating the key (the old one is invalidated immediately) or revoking it outright. Store the key only in server-side environment variables or a secrets manager — never in frontend code, an app bundle, or a public repository.

Feasibility

Q: Can an idempotency key stop me from accidentally clicking "generate" twice?

A: No. If each click generates its own Idempotency-Key, the server treats them as two independent business requests and bills each one. An idempotency key guards against "duplication caused by a network issue automatically retrying the same request" — it doesn't stop a user from initiating a request twice; debouncing that has to be handled in your own application code.

Q: Should every error be blindly retried three times?

A: No. Error codes like 400, 401, 402, 404, 409, and 422 represent clear-cut problems with parameters, authentication, balance, or key reuse — retrying will just keep returning the same error and waste a request. Only transient errors like timeouts, 5xx, and 429 are worth retrying alongside an idempotency key.

Use Cases

Q: How should an e-commerce team design Idempotency-Keys for batch image generation?

A: A common approach is to concatenate identifiers that are already unique in your business logic — for example, "product SKU plus current batch number" — or to just use a UUID. This ensures the key for a given product's batch of tasks never collides with another product's, and retries can reliably reuse the exact same key.

Q: A short-video team runs tasks concurrently and keeps hitting the concurrency limit — what should they do?

A: The API and the web app share the same account's concurrency limit. Receiving a concurrency-related 429 (concurrent_limit) means the current concurrency is maxed out — wait per Retry-After and then retry with the same key. Flux Art hasn't published a specific concurrency limit number, so when planning batch jobs, it's best to build in queuing rather than pushing concurrency to the max.

Access

Q: How do you troubleshoot a 409 idempotency_key_reused error?

A: It means this key was already bound to a different set of request parameters. First check whether your key-generation logic has a bug — for instance, all requests sharing one fixed string — and fix it so every business request generates its own independent key. Don't reuse any key that was misused in the past.

Q: If reconciliation shows points don't match the task count, where should you start looking?

A: First check whether usage.points_charged and usage.points_refunded were both fully recorded in the responses, then page through GET /tasks to verify the status of every task in the account. If a call hit Idempotent-Replayed, it means that call didn't incur a new charge — it's easy to mistake this for "overcharging," so pull these replayed requests out and review them separately during reconciliation.