Integration · Python

Python image generation without paying twice for the same click

Small client, stable Idempotency-Key per business operation, bounded retries. Safety and validation errors stop — they don’t hop.

Opaque matte lilac ceramic perfume bottle with stopper on a warm stone plinth
FLUX DevPrismatic perfume study960 × 1472
AT A GLANCE

A Python image generation client should treat each user action as one billed operation, even when HTTP retries happen.

Opaque matte lilac ceramic perfume bottle with stopper on a warm stone plinth
Prismatic perfume study

“Luxury solid ceramic perfume bottle, completely opaque matte lilac glaze, rectangular modern flacon, matching ceramic stopper, thin polished chrome collar, warm travertine plinth, soft peach studio backdrop, commercial product photography, portrait composition”

FLUX Dev · premium · 960 × 1472
01

Create one client with explicit configuration

Load the key from the server environment and create an httpx client with a base URL and timeout. Do not instantiate a new client for every item in a large batch; connection pooling reduces unnecessary handshakes. Do not bake the API key into a notebook that will be committed or shared.

A typed wrapper should accept your product-level operation ID. That ID becomes the idempotency key, making a network retry safe. Randomly generating a new key after each timeout defeats the protection.

Minimal typed clientpython
from dataclasses import dataclass
import httpx

@dataclass
class RenderRouteClient:
    api_key: str
    base_url: str = "https://renderroute.app"

    def generate(self, payload: dict, operation_id: str) -> dict:
        with httpx.Client(base_url=self.base_url, timeout=90) as client:
            response = client.post(
                "/v1/images/generations",
                headers={
                    "Authorization": f"Bearer {self.api_key}",
                    "Idempotency-Key": operation_id,
                },
                json=payload,
            )
            response.raise_for_status()
            return response.json()
02

Retry transport failures, not policy decisions

The RenderRoute server already retries eligible provider errors and may fall back. The Python client should only retry when it did not receive a definitive application response, or when the API returns a documented transient status such as 502 or 503. Reuse the same idempotency key.

Do not retry 400 safety rejections, 401 authentication failures, 409 idempotency conflicts, or 422 validation errors without changing the underlying issue. Respect 429 backoff rather than starting parallel retry storms.

StatusClient actionIdempotency key
Network disconnectRetry with backoffReuse
502/503Retry within product budgetReuse
429Wait, then retryReuse
400/401/409/422Fix or stopDo not blind-retry
03

Copy accepted URL output to storage you control

Provider output URLs can have limited retention. After moderation and product approval, download the asset through a controlled worker, validate content type and size, scan it, compute a hash, and store it in an object bucket with a random key. Serve through your CDN with appropriate access controls.

Never let a user-supplied URL become an unrestricted server-side fetch. The current text-to-image endpoint returns provider URLs; future image-input features need strict allowlists, signed uploads, and SSRF defenses.

  • Validate MIME type and magic bytes
  • Limit download size and duration
  • Strip unneeded metadata according to policy
  • Store provenance and request ID
  • Apply lifecycle and deletion rules
04

Prefer controlled concurrency over one enormous request

The API caps images per request because giant batches amplify timeout, cost, and partial-failure problems. For a catalog or evaluation set, submit small idempotent operations with a bounded worker pool. Record each operation independently so one failure does not erase the whole batch.

When throughput grows, add a queue, per-tenant concurrency, and a dead-letter workflow. Scale provider limits and moderation capacity together; generation without matching safety capacity should backpressure rather than fail open.

FAQ

Questions about Python image generation API

Which Python HTTP library should I use?

The reference uses httpx because it supports both synchronous and asynchronous clients with explicit timeouts.

Should my Python client call Runware directly?

Only for isolated provider experiments. Product clients should call RenderRoute so policy, dimensions, metrics, and fallback behavior stay centralized.

How long are output URLs valid?

Retention depends on the provider and settings. Treat them as temporary and copy approved assets to owned storage promptly.

Can I send a list of hundreds of prompts?

Use a bounded queue of small requests. The public endpoint intentionally limits n per call.

One stable contract

Put the routing layer between your app and the model fleet.