Developer guidesImage generation
Browse this guide
OpenAI-style Images API

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

Send your team-issued key as a Bearer token. Do not send the upstream provider key.

Request safety

At-most-once dispatch

Every request needs a unique idempotency key so an uncertain retry cannot create a duplicate charge.

Metering

Image-unit pricing

The gateway reserves spend before dispatch and settles against the number of images returned.

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.

Terminal
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

This endpoint currently supports text-to-image generation. Image input, edits, masks, variations, multipart uploads, and streaming are not supported.

Two separate credential layers

A Super Admin configures the upstream provider credential once. Teams and users authenticate only with their Moca Router API keys; those keys carry team access, rate limits, and billing policy without exposing the provider credential.

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.

Capabilities request
# 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"
Read 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

Unsupported optional values are rejected with a 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.

modelrequired
The exact image model ID. The model must be active, allowed for the API key's team, and support the image_generation operation.
promptrequired
A non-empty UTF-8 prompt. The deployment default limit is 32 KiB; the operator may configure a lower or higher limit.
noptional
Integer number of images. Defaults to 1 and cannot exceed the model's maxN.
sizeoptional
One of the model's advertised sizes, such as 1024x1024 or auto.
qualityoptional
One of the advertised quality names, for example standard, when supported.
output_formatoptional
Raster output format. Supported values are model-dependent subsets of png, jpeg, and webp.
response_formatoptional
Either b64_json or url when advertised by the model. Each returned item contains exactly one representation.
backgroundoptional
One of auto, opaque, or transparent when the model advertises background control.
useroptional
An opaque end-user identifier of at most 128 UTF-8 bytes. Avoid names, email addresses, or other personal data.
streamoptional
Streaming is not supported. Omit this field or set it to false.

Required headers

Send 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+)

generate-image.mjs
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

generate_image.py
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

Do not embed a Moca Router key in browser JavaScript, a mobile bundle, or a public repository. Call the gateway from your backend and apply your own end-user authorization before forwarding a request.

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.

Example base64 response
{
  "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

If the gateway cannot prove whether the provider accepted a dispatched request, it returns 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

Query the model-capabilities endpoint with the same team key that will make the request. Its pricing.customerChargeRates is the effective public pricing view after team and member policy.

Marketplace subscriptions

Image generation is not currently available for AWS Marketplace subscriptions. The gateway returns 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 response
{
  "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

The selected provider receives the content needed to perform generation. Moca Router's pass-through behavior does not change that provider's own logging, abuse-monitoring, training, or retention policy. Review the provider agreement for your deployed upstream before sending sensitive content.
  • 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-id and 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.