Generate and save an image with Python
Call Jevrouter's native image API from Python, read SSE completion events, save a PNG and understand image usage receipts and balance reservations.
By Jevrouter · Updated
Choose the native Images endpoint
Jevrouter exposes POST /v1/images and the alias /v1/images/generations. The API is compatible with the documented Jevrouter image request contract; do not assume an arbitrary image SDK's parameters can be forwarded unchanged.
Use stream:true for long generations. The connection sends keepalives and then a completion event containing the result. This is completion-event streaming, not a sequence of partial image previews. The following example uses only Python's standard library.
Generate one PNG and save it locally
This example requests one image with a fixed model, a square aspect ratio and PNG output. It prints the request ID and provider usage receipt. It does not automatically retry if the outcome is unknown.
The max_cost_usd value limits the accepted reservation. If it is below the current conservative quote, the request fails before generation. Model prices and provider availability can change after this guide was written.
import base64
import json
import os
import urllib.request
import uuid
from pathlib import Path
body = {
"model": "black-forest-labs/flux.2-klein-4b",
"prompt": "A small lime green paper boat on calm water, simple illustration, no text.",
"n": 1, "aspect_ratio": "1:1", "output_format": "png",
"stream": True, "jev": {"max_cost_usd": "0.25"},
}
request = urllib.request.Request(
"https://api.jevrouter.io/v1/images",
data=json.dumps(body).encode(),
headers={
"Authorization": "Bearer " + os.environ["JEVROUTER_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": str(uuid.uuid4()),
}, method="POST",
)
completed = False
with urllib.request.urlopen(request, timeout=310) as response:
for raw_line in response:
line = raw_line.decode("utf-8").strip()
if not line.startswith("data:"):
continue
payload = line[5:].strip()
if payload == "[DONE]":
break
result = json.loads(payload)
if "error" in result:
raise RuntimeError(result["error"].get("message", "Image generation failed"))
if "data" in result:
image = result["data"][0]
if image.get("media_type", "image/png") != "image/png":
raise RuntimeError("Unexpected output type")
Path("generated.png").write_bytes(base64.b64decode(image["b64_json"], validate=True))
print("Request:", result["id"], "Usage:", result.get("usage"))
completed = True
if not completed:
raise RuntimeError("No completed image. Inspect request status before retrying.")Add reference images when the model supports them
Use input_references with image_url entries. URLs must use HTTPS; PNG, JPEG and WebP data URLs are also accepted. Check the selected model's minimum and maximum reference count. An editing-only provider can require an image even when the request contains a detailed prompt.
Jevrouter limits the JSON body to 20 MiB. Base64 increases the size of a local file, so the Playground caps selected files at 12 MiB in total. Images and reference contents are not kept as a server-side project gallery.
"input_references": [
{"type": "image_url", "image_url": {"url": "https://jevrouter.io/examples/flux-klein-boat.png"}}
]Read the receipt rather than the reservation
Image providers can charge per image, megapixel, request or token, with different prices for quality and resolution variants. The gateway reserves conservatively and releases the unused amount when the provider receipt is settled.
In a September 21, 2026 production check, FLUX.2 Klein 4B returned a 1024×1024 PNG with a $0.014 receipt after a $0.224 reservation. This is one historical call, not a promise about future generations.
Models mentioned in this guide
Try it in your project.
Choose a model, create a scoped API key and inspect the result in Requests.
Open console ↗