faucet
Request access
Guides

Images

Generate and edit pictures across OpenAI, Google and Black Forest Labs, in the OpenAI images envelope.

Generating a picture

POST /v1/images/generations takes the same key and the same namespaced slugs as everything else, and returns OpenAI's images envelope — data[].b64_json, with model and a usage object beside it:

curl https://api.intfaucet.com/v1/images/generations \
  -H "Authorization: Bearer $FAUCET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-image-2",
    "prompt": "a leaky bucket, watercolour",
    "size": "1024x1024",
    "quality": "medium"
  }'

From the AI SDK it is imageModel:

import { generateImage } from 'ai';

const { image, usage } = await generateImage({
  model: faucet.imageModel('openai/gpt-image-2'),
  prompt: 'a leaky bucket, watercolour',
});

Served by OpenAI, Google and Black Forest Labs. openai/gpt-image-2.5-flare and openai/gpt-image-2.5-sunburst — Flare for everyday generation, Sunburst where a picture has to survive a long chain of edits — alongside openai/gpt-image-2 and its siblings; the Gemini image models — google/gemini-3-pro-image, google/gemini-3.1-flash-image and google/gemini-3.1-flash-lite-image; and the FLUX.2 family — bfl/flux-2-max, bfl/flux-2-pro, bfl/flux-2-flex, bfl/flux-2-klein-9b and bfl/flux-2-klein-4b, which take different parameters and are billed differently enough to have their own section below.

model is the slug that answered, in Faucet's own namespaced spelling. OpenAI reports null in this field and Gemini has no field for it, so Faucet stamps its own — which means a spend ledger can record the model that served a request rather than only the one that was asked for.

Billing is tokens — and the picture is the output tokens

FLUX.2 is billed in credits instead; see its section below. This is the one place the parallel with the chat endpoint holds more exactly than people expect. Neither OpenAI nor Google bills per image: OpenAI quotes gpt-image-2 at $5.00/1M input and $30.00/1M output, Google quotes gemini-3-pro-image at $2.00/1M and $120.00/1M, and the familiar per-image figures you see quoted elsewhere are derived — each size-and-quality tier consumes a fixed number of output tokens, and multiplying by the output rate reproduces them. So the price of an image is decided entirely by the tier you ask for, and the same usage object and the same console line explain it as for any other request.

The two providers size an image differently

This is the one place a model swap is not purely a string change:

OpenAIGoogle
Sizesize, any conforming resolutionsize, square only — or an aspect ratio
Qualityquality: low, medium, high, auto — and xhigh, max on GPT Image 2.5no quality tier; resolution is the lever
Multiple imagesnone image per request

Ask the gateway rather than copying this table

GET /v1/models/{id} publishes sizes (or min_edge where width and height are free), qualities, max_n, output_formats and max_input_images for the models Faucet itself narrows — the Gemini image models and FLUX.2. OpenAI image models publish no block, because they are passthrough and OpenAI stays authoritative about its own endpoint. See Model capabilities.

An OpenAI image is a resolution plus a quality tier. A Gemini image is an aspect ratio times a resolution tier — 1K, 2K, 4K, and 512 on some models — and the pixel dimensions fall out of that pair. Square sizes mean the same thing in both systems, so 1024x1024 and 2048x2048 work unchanged on either. Anything else does not translate, and Faucet refuses it rather than quietly returning a different shape:

{
  "model": "google/gemini-3-pro-image",
  "prompt": "a leaky bucket, watercolour",
  "provider_options": {
    "google": { "aspect_ratio": "16:9", "image_size": "4K" }
  }
}

Ratios are 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9 and 21:9. Which resolution tiers a given model offers is per model — the Pro model starts at 1K, and gemini-3.1-flash-lite-image serves 1K and nothing else — so asking for a tier a model cannot produce is a 400 naming the ones it can, rather than a smaller picture than you asked for and a bill for it.

The same goes for the rest: quality on a Gemini model is a 400 explaining that resolution is the lever, and n above 1 is a 400 rather than one image where you expected three. A parameter that cannot be honoured is refused, never dropped — on this endpoint a silently ignored parameter is a charge you did not agree to.

Background, output format and response format

These three are accepted on both endpoints and are worth stating plainly, because they behave differently across the three providers:

OpenAIGoogleFLUX.2
backgroundtransparent on GPT Image 2.5; opaque and auto anywhereopaque and auto onlyopaque and auto only
output_formatpng, jpeg, webpnot adjustable — a 400jpeg, png, webp
response_formatb64_json, urlb64_json onlyb64_json only

background: "transparent" with output_format: "png" on openai/gpt-image-2.5-flare is how you get a cutout with a real alpha channel. openai/gpt-image-2.5-sunburst does the same at the same price, and is the better of the two when edit precision matters more than latency.

Not `openai/gpt-image-2`

Transparency on that model was always an OpenAI preview, and OpenAI withdraws it on 2026-09-30. Faucet refuses that one combination ahead of the date — a 400 naming the model to move to, rather than a forwarded request that comes back as a picture with no alpha channel. Nothing else about gpt-image-2 changes: opaque, auto, and omitting background entirely all work exactly as before.

Gemini cannot produce a cutout at all, so asking it for one is a 400 naming the model that can — rather than a 200 and an opaque JPEG, which is what a picture with no alpha looks like until you inspect it.

FLUX.2

bfl/flux-2-max, bfl/flux-2-pro, bfl/flux-2-flex, bfl/flux-2-klein-9b and bfl/flux-2-klein-4b serve both /v1/images/generations and /v1/images/edits, in the same OpenAI envelope as everything else: you send the same fields and get data[].b64_json back.

The parameters map differently, and anything that cannot be honoured is refused rather than quietly dropped:

OpenAI parameterFLUX.2
sizeWIDTHxHEIGHT becomes width / height, each at least 64px; auto or omitted lets the model choose
output_formatjpeg, png, webp
n1 only
qualityrefused — FLUX.2 has no quality tier
backgroundauto and opaque; transparent is refused
response_formatb64_json only
image (edits)up to 8 input pictures, or 4 on the klein models
mask (edits)refused — FLUX.2 has no masked edit

Billing is credits, not tokens, which is the one place the token parallel above does not hold. FLUX.2 reports no token counts at all; it reports a cost in provider credits worth $0.01 each, and that figure is what the request is billed on. A credit-billed request therefore debits none of your tokens-per-minute allowance — there are no tokens to debit — so it is bounded by your requests-per-minute allowance and your credit balance alone.

Upstream it is a job queue, and you never see it. A FLUX request answers with an id and a polling URL, and the picture exists only once polling reports it ready. Faucet submits, polls and downloads within your single request, so what you get back is the same synchronous response as any other image model — at the cost of a longer wall-clock wait on the larger models.

Editing a picture

POST /v1/images/edits is the same endpoint with a picture going in. Send the image you already have and say what to change about it:

curl https://api.intfaucet.com/v1/images/edits \
  -H "Authorization: Bearer $FAUCET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemini-3-pro-image",
    "prompt": "move the apartment building to the centre of the square",
    "image": "data:image/png;base64,iVBORw0KGgo…"
  }'

Both JSON and multipart/form-data are accepted. OpenAI's own edits endpoint is multipart only, so their SDK works here unchanged; JSON is for the clients that already post JSON everywhere else and hold the bytes in hand. The two are equivalent — pick whichever you already have.

curl https://api.intfaucet.com/v1/images/edits \
  -H "Authorization: Bearer $FAUCET_API_KEY" \
  -F "model=openai/gpt-image-2" \
  -F "prompt=make the sign read OPEN" \
  -F "image=@storefront.png"

image takes one picture or several — a bare base64 string, a data: URL, or an array of either. Several inputs is how you ask a model to combine them. PNG, JPEG and WebP are accepted; the format is read from the bytes rather than from what you called the file, so a mislabelled upload still works. A remote https:// URL is not accepted: Faucet does not fetch images on your behalf.

mask is OpenAI-only inpainting — transparent where the model may redraw, opaque where it may not. Gemini has no equivalent, so a mask sent to a Gemini model is a 400 rather than a mask quietly ignored.

An edit is billed at two input rates on OpenAI, and this is the one number that surprises people. OpenAI charges $8.00/1M for image input against $5.00/1M for text on gpt-image-2, and an edit's input is mostly picture — so the input half of an edit costs roughly 60% more per token than the same count of prompt text. The response says so: usage.input_tokens_details.image_tokens is the picture's share of usage.input_tokens. Google quotes one input rate covering both, so the split is reported as zero there and the arithmetic is simpler.

Sending an image to `/v1/images/generations` is a `400`

Generation draws from the prompt alone; if image, images, image_url or mask appears on that endpoint the request is refused with a message pointing here. That refusal exists because the alternative — accepting the field, ignoring it, and returning a picture invented from the words in your instruction — looks exactly like an edit that came out badly.

Images and your rate limit

Image output tokens are the picture, and they are counted like any others. One high-quality 1024×1024 image is a few thousand output tokens, so a modest tokens-per-minute allowance can be spent in a handful of pictures. See Errors and limits.