Browse this guide
Generate images through Moca Router
Call one gateway endpoint with your Moca Router API key. Team permissions, model routing, provider credentials, quotas, and image-unit billing stay behind the gateway.
Authentication
One gateway key
Request safety
At-most-once dispatch
Metering
Image-unit pricing
Make your first request
Create an API key in the dashboard, choose an image model enabled for your team, and send a JSON request. The example model below is gemini-2.5-flash-image; use the exact ID shown in the model catalog if your team uses another model.
export MOCA_ROUTER_API_KEY="sk-mocarouter-..."
curl https://staging.mocarouter.com/api/proxy/v1/images/generations \
-H "Authorization: Bearer $MOCA_ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: img-$(uuidgen)" \
-d '{
"model": "gemini-2.5-flash-image",
"prompt": "A quiet reading room overlooking Tokyo at dusk"
}'Generations only
Two separate credential layers
Check before sending
Read model-specific capabilities
Image models do not all accept the same size, quality, format, background, or result representation. List the model IDs visible to the team, then query a candidate with the authenticated capabilities endpoint before constructing optional parameters. A usable image model returns modality: image and the image_generation operation.
# List model IDs available to this team
curl https://staging.mocarouter.com/api/proxy/v1/models \
-H "Authorization: Bearer $MOCA_ROUTER_API_KEY"
# Inspect one candidate before generating
curl --get https://staging.mocarouter.com/api/proxy/v1/model-capabilities \
-H "Authorization: Bearer $MOCA_ROUTER_API_KEY" \
--data-urlencode "model=gemini-2.5-flash-image"capabilities.image_generation for maxN, sizes, qualities, outputFormats, responseFormats, and backgrounds. The same response includes the effective customer unit-pricing rules for that team.Never assume another model's options
400 response. Omitting an optional field selects that model's configured default; it does not guarantee the same default across models.JSON request
Supported request fields
The API rejects unknown fields. Field names follow the OpenAI Images API shape, while accepted values come from the selected model's capability record.
modelrequiredimage_generation operation.promptrequirednoptional1 and cannot exceed the model's maxN.sizeoptional1024x1024 or auto.qualityoptionalstandard, when supported.output_formatoptionalpng, jpeg, and webp.response_formatoptionalb64_json or url when advertised by the model. Each returned item contains exactly one representation.backgroundoptionalauto, opaque, or transparent when the model advertises background control.useroptionalstreamoptionalfalse.Required headers
Authorization: Bearer <Moca Router key>, Content-Type: application/json, and an Idempotency-Key containing 8–128 printable ASCII characters.Server-side examples
JavaScript and Python
Generate a new idempotency key for each intended image generation. Keep the same key only when retrying an attempt whose delivery result is uncertain.
JavaScript (Node.js 18+)
import { randomUUID } from "node:crypto";
import { writeFile } from "node:fs/promises";
const response = await fetch("https://staging.mocarouter.com/api/proxy/v1/images/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MOCA_ROUTER_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(),
},
body: JSON.stringify({
model: "gemini-2.5-flash-image",
prompt: "A quiet reading room overlooking Tokyo at dusk",
}),
});
const payload = await response.json();
if (!response.ok) {
throw new Error(payload.error?.message ?? `HTTP ${response.status}`);
}
const image = payload.data[0];
if (image.b64_json) {
const extension = payload.output_format === "jpeg"
? "jpg"
: (payload.output_format ?? "bin");
await writeFile("image." + extension, Buffer.from(image.b64_json, "base64"));
} else {
console.log("Temporary image URL:", image.url);
}Python
import base64
import os
import uuid
import requests
response = requests.post(
"https://staging.mocarouter.com/api/proxy/v1/images/generations",
headers={
"Authorization": f"Bearer {os.environ['MOCA_ROUTER_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"model": "gemini-2.5-flash-image",
"prompt": "A quiet reading room overlooking Tokyo at dusk",
},
timeout=180,
)
payload = response.json()
if not response.ok:
raise RuntimeError(payload.get("error", payload))
image = payload["data"][0]
if "b64_json" in image:
output_format = payload.get("output_format", "bin")
extension = "jpg" if output_format == "jpeg" else output_format
with open(f"image.{extension}", "wb") as file:
file.write(base64.b64decode(image["b64_json"], validate=True))
else:
print("Temporary image URL:", image["url"])Keep API keys on the server
Handle both result formats
A successful response uses an OpenAI-compatible data array. Each item contains exactly one of b64_json or url, plus an optional revised_prompt. Usage appears only when the provider reports it.
{
"created": 1789552800,
"data": [
{
"b64_json": "iVBORw0KGgoAAA...",
"revised_prompt": "A quiet reading room..."
}
],
"output_format": "png",
"quality": "standard",
"size": "1024x1024",
"usage": {
"input_tokens": 18,
"output_tokens": 1290,
"total_tokens": 1308
}
}b64_json
Decode the returned bytes
Decode base64 directly and save it with the returned output_format. Avoid logging the encoded payload.
url
Treat it as temporary
Fetch or present the HTTPS URL promptly. Availability and expiry are controlled by the upstream provider.
Diagnostic response headers include x-mocarouter-request-id, and may include x-mocarouter-routed-model and x-mocarouter-provider-request-id. Record these IDs—not image content—when contacting support.
Responses are marked Cache-Control: no-store. Rate-limited responses may include Retry-After and X-RateLimit-* headers.
At-most-once dispatch
Idempotency and safe retries
- Create one random key per intended generation. UUIDs are a good default.
- If the connection times out before you receive a response, retry the identical request with the same key.
- Never reuse a key with a changed prompt or parameter set; the gateway returns
409 idempotency_key_conflict. - If an identical request is still running, the gateway returns
409 idempotency_request_in_progress. Wait before checking again. - Successful image bytes are not cached for replay. A repeated completed key returns
410 idempotent_result_unavailable; use a new key only when you intentionally want a new generation and charge.
An unknown outcome is intentionally not re-dispatched
409 idempotency_outcome_unknown instead of sending a second generation. Do not automatically switch to a new key, because that could generate and bill twice; retain the request ID and contact support. A confirmed provider failure also needs a new key before an intentional retry.Precise metering
Billing and quota behavior
Image generation is billed separately from text-token quotas. Effective prices are selected from the model's image-unit rules and request dimensions such as size, quality, output format, response format, and background.
- Before upstream dispatch, Moca Router reserves the maximum customer charge for the requested
n. - After a valid provider response, the hold is settled against the actual number of returned images.
- Provider token usage can be recorded for cost accounting and returned in
usage, but customer-facing image pricing is exposed as USD per image unit. - Team, API-key, account, request-per-minute, image-unit-per-minute, concurrency, balance, and budget controls can reject a request before dispatch.
Inspect the price before production
pricing.customerChargeRates is the effective public pricing view after team and member policy.Marketplace subscriptions
403 marketplace_image_dimension_unavailable for those teams.Errors and troubleshooting
Image-route errors use a structured envelope with message, type, param, and code. Authentication middleware errors may use a shorter envelope.
{
"error": {
"message": "size is not supported by this model",
"type": "invalid_request_error",
"param": "size",
"code": "unsupported_size"
}
}400 / 413Fix the requestMissing headers, unsupported fields or values, invalid JSON, or a prompt above the configured byte limit.401 / 403Check accessMissing, invalid, expired, blocked, or team-restricted API key; model not allowed for the team.409 / 410Follow idempotency stateRequest in progress, key conflict, unknown outcome, confirmed failure, or a completed result that is not replayable.429Back offRequest, image-unit, concurrency, provider, balance, or budget admission limit. Honor Retry-After when present.502–504Retry selectivelyInvalid upstream response, unavailable route, disabled feature, provider capacity, timeout, or incomplete model/pricing configuration.Pass-through content path
Data handling and retention boundaries
The image generation path processes the prompt and provider response to validate and return the result, but its application database does not store the raw prompt, generated image bytes, provider image URL, or raw idempotency key. It stores operational and billing metadata such as keyed request digests, request state, model, dimensions, usage, cost, and request IDs.
Upstream provider policy still applies
- Do not place API keys, passwords, personal identifiers, or regulated secrets in prompts.
- Avoid logging request bodies, base64 output, or provider URLs in your own application.
- Store only the generated output you actually need and apply your own access and deletion policy.
- Use
x-mocarouter-request-idand the idempotency key—not customer content—for support correlation.
Ready to integrate?
Choose a model and create an API key
Confirm the model is enabled for your team, inspect its capabilities and effective price, then send a minimal request with a fresh idempotency key.
