A Python image generation client should treat each user action as one billed operation, even when HTTP retries happen.
“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 × 1472Create 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.
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()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.
| Status | Client action | Idempotency key |
|---|---|---|
| Network disconnect | Retry with backoff | Reuse |
| 502/503 | Retry within product budget | Reuse |
| 429 | Wait, then retry | Reuse |
| 400/401/409/422 | Fix or stop | Do not blind-retry |
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
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.
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.