DocsOpen Moon AI
Browse the docs

Images

Reference for POST /v1/images/generations and POST /v1/images/edits: create and edit images in the OpenAI format, with sizes, formats, limits and costs.

On this page

Two endpoints in the format of the OpenAI Images API: POST /v1/images/generations creates images from a description, and POST /v1/images/edits creates them from one or more images. Images come back in the response, in base64: Moon AI keeps no copy and does not provide a hosted URL.

Create an imageLink to the Create an image section

HTTP
POST https://api.realmoon.ai/v1/images/generations
  • Authentication: an sk-moon-… key with the inference scope (see Authentication).
  • Body: JSON, 1 MB at most.
  • Response: an image object (see Response).

ParametersLink to the Parameters section

ParameterTypeRequiredDescription
modelstringyesAn image model from GET /v1/models?type=image.
promptstringyesDescription of the image, 8,000 characters at most.
nintegernoNumber of images, from 1 to 4. 1 by default. Billed per image produced.
sizestringnoauto or WIDTHxHEIGHT, from 64 to 8,192 pixels per side. Used to pick the closest aspect ratio and size the model offers (see Size and aspect ratio).
aspect_ratiostringnoOne of the model’s aspect ratios (aspect_ratios in /v1/models), for example 1:1, 16:9, 2:3. Takes precedence over the aspect ratio derived from size.
image_sizestringno1K, 2K or 4K, for models that offer several sizes (image_sizes). Takes precedence over the size derived from size.
qualitystringnoauto, low, medium, high, standard or hd. Accepted for compatibility, with no effect: the model chooses on its own.
response_formatstringnob64_json (default) or url. With url, the image comes as a data: URL.
streambooleannoOnly false is accepted.

The user, style, moderation, background, output_compression, output_format, partial_images and input_fidelity parameters are accepted and have no effect. Any other parameter is rejected with 400 unknown_parameter. An image sent in image or images is rejected here: use /v1/images/edits.

ExampleLink to the Example section

cURL
curl https://api.realmoon.ai/v1/images/generations \
  -H "Authorization: Bearer $MOONAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "google/gemini-3.1-flash-image",
        "prompt": "A retro poster of a rocket above Paris",
        "size": "1024x1536"
      }' \
  | jq -r '.data[0].b64_json' | base64 --decode > poster.png
Python
import base64
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.realmoon.ai/v1", api_key=os.environ["MOONAI_API_KEY"])

img = client.images.generate(
    model="google/gemini-3.1-flash-image",
    prompt="A retro poster of a rocket above Paris",
    size="1024x1536",
    # Moon AI-specific parameter: passed through extra_body.
    extra_body={"image_size": "2K"},
)
with open("poster.png", "wb") as f:
    f.write(base64.b64decode(img.data[0].b64_json))
JavaScript
import fs from 'node:fs';
import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://api.realmoon.ai/v1', apiKey: process.env.MOONAI_API_KEY });

const img = await client.images.generate({
  model: 'google/gemini-3.1-flash-image',
  prompt: 'A retro poster of a rocket above Paris',
  size: '1024x1536',
  // Moon AI-specific parameter, sent as is.
  image_size: '2K',
});
fs.writeFileSync('poster.png', Buffer.from(img.data[0].b64_json, 'base64'));

Size and aspect ratioLink to the Size and aspect ratio section

When you give size without aspect_ratio or image_size:

  • the aspect ratio used is the model’s closest match to the width-to-height ratio;
  • the size used is 1K if the longest side is 1,100 pixels or less, 2K up to 2,200 pixels, and 4K beyond that (or the model’s largest size).

So the image produced can have slightly different dimensions from size. With no size, aspect_ratio or image_size, the model decides.

Edit an imageLink to the Edit an image section

HTTP
POST https://api.realmoon.ai/v1/images/edits
  • Authentication: an sk-moon-… key with the inference scope.
  • Body: multipart/form-data (with the Content-Length header) or JSON, 90 MB at most.
  • Response: an image object (see Response).

ParametersLink to the Parameters section

All the generation parameters apply, plus the images:

ParameterTypeRequiredDescription
imagefile, string or arrayyesIn multipart: one or more files in the image or image[] field. In JSON: a string or a list of strings (base64 data: URL, bare base64, or https:// URL).
imagesarraynoIn JSON, the OpenAI shape: [{"image_url": "…"}]. Added to image.
masknoNot accepted (400 unsupported_parameter): describe the change in the prompt instead.
RuleValue
Image typesPNG, JPEG, WebP, GIF
Size of one image20 MB and 40 megapixels at most
Number of imagesThe model’s max_input_images in /v1/models
Body size90 MB at most

An image given as an https:// URL is fetched by the model provider, never by Moon AI.

ExampleLink to the Example section

cURL
curl https://api.realmoon.ai/v1/images/edits \
  -H "Authorization: Bearer $MOONAI_API_KEY" \
  -F model=google/gemini-3.1-flash-image \
  -F prompt="Same photo, in black and white" \
  -F image=@photo.png
Python
edit = client.images.edit(
    model="google/gemini-3.1-flash-image",
    image=open("photo.png", "rb"),
    prompt="Same photo, in black and white",
)
with open("photo-bw.png", "wb") as f:
    f.write(base64.b64decode(edit.data[0].b64_json))

# Several images: pass a list.
combo = client.images.edit(
    model="google/gemini-3.1-flash-image",
    image=[open("product.png", "rb"), open("setting.png", "rb")],
    prompt="The product from the first image placed in the setting of the second",
)
JavaScript
const edit = await client.images.edit({
  model: 'google/gemini-3.1-flash-image',
  image: fs.createReadStream('photo.png'),
  prompt: 'Same photo, in black and white',
});
fs.writeFileSync('photo-bw.png', Buffer.from(edit.data[0].b64_json, 'base64'));

The same call in JSON, with one image in base64 and one image at a URL:

JSON body
{
  "model": "google/gemini-3.1-flash-image",
  "prompt": "The product from the first image placed in the setting of the second",
  "images": [
    { "image_url": "data:image/png;base64,iVBORw0KGgo…" },
    { "image_url": "https://example.com/setting.jpg" }
  ]
}

ResponseLink to the Response section

Both endpoints return the same object.

Response
{
  "created": 1793577600,
  "model": "google/gemini-3.1-flash-image",
  "data": [
    { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…", "output_format": "png" }
  ],
  "usage": { "images": 1, "credits": 650 }
}
FieldTypeDescription
createdintegerTimestamp in Unix seconds.
modelstringThe model you called.
data[].b64_jsonstringThe image in base64, with response_format: "b64_json".
data[].urlstringThe image as a data: URL, with response_format: "url".
data[].output_formatstringFile format: png, jpeg, webp, gif or svg.
usage.imagesintegerNumber of images produced.
usage.creditsintegerCredits charged for the request.

When you ask for several images and some of them fail, the response contains only the ones that were produced: compare usage.images with n.

Headers: X-Moon-Request-Id, X-Moon-Prompt-Storage: none, X-Moon-Blur: not_applied (Moon Blur does not apply to images or to their description) and Cache-Control: no-store.

ModelsLink to the Models section

List as of November 5, 2026; the current list, with prices, comes from GET /v1/models?type=image.

ModelAspect ratiosSizesInput images
google/gemini-3.1-flash-image (Nano Banana 2)1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:91K, 2K, 4K8
google/gemini-3-pro-image (Nano Banana Pro)1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:91K, 2K, 4K8
google/gemini-3.1-flash-lite-image1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:31K, 2K, 4K4
openai/gpt-image-2, openai/gpt-image-1-mini1:1, 3:2, 2:3single size4
black-forest-labs/flux.2-pro, flux.2-max, flux.2-klein-4b, flux-3-image1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3single size4
bytedance-seed/seedream-5-0-pro, seedream-5-0-lite1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3single size4
qwen/qwen-image-3, x-ai/grok-imagine-image-2.01:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3single size4
recraft/recraft-v4.1, recraft/recraft-v4.1-vector (SVG output)1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3single size4

image_size is accepted only by models with several sizes.

CostsLink to the Costs section

  • Before the call, the request holds the most it can cost: max_credits_per_unit (or the value for the requested size) times the number of images, plus the images you send.
  • Afterward, you pay the actual cost reported by the provider (or, failing that, the list price), and the rest of the hold is released right away.
  • A request that fails, is refused before anything is created, or is cut off by our timeout costs nothing.
  • A model that answers with text instead of an image (safety refusal, misunderstood prompt) charges for the text it wrote, and the API responds with 400 content_policy_violation: rephrase the prompt.

See Costs and wallet for holds and settlement.

LimitsLink to the Limits section

  • All the images in a request are made at the same time; the request responds within about 90 seconds at most.
  • At most 8 image requests in flight at once per workspace (beyond that: 429 too_many_concurrent, Retry-After: 5).

ErrorsLink to the Errors section

HTTPcodeMeaning
400missing_required_parametermodel, prompt or image is missing.
400unknown_parameterUnknown parameter (param names it).
400unsupported_valueA value the model does not accept (n, size, aspect_ratio, image_size, quality, response_format).
400unsupported_parametermask, stream, image_size on a single-size model, an image sent to /generations, or a parameter the model rejects (with a hint).
400unsupported_modelThe model does not do editing.
400string_above_max_lengthPrompt longer than 8,000 characters.
400too_many_imagesMore images than max_input_images.
400invalid_imageUnreadable image, wrong type, or more than 40 megapixels.
400content_policy_violationThe model’s safety system rejected the image.
400invalid_request_errorThe model rejected the request without further detail.
400nullInvalid JSON body, invalid base64, unexpected file field or unreadable form.
403org_policyYour organization’s rules refuse this model.
404model_not_foundUnknown model, or one that does not serve this endpoint.
411length_requiredMultipart upload without a Content-Length header.
413request_too_large, file_too_largeBody or image too large.
429too_many_concurrentToo many image requests in flight in the workspace.
429upstream_rate_limitedThe model is overloaded: retry after Retry-After (10 seconds).
502, 504upstream_error, upstream_timeoutThe model failed or did not respond in time.
503upstream_unavailableThe service is temporarily unavailable.

Key, balance and spend cap errors are in Errors.

See alsoLink to the See also section

Moon AI

Moon AI in action

0:00

Explore

Screenshots of chat.realmoon.ai taken on October 29, 2026, with fictional data.

Moon AI

Your preferences

Visits counted without cookies.

Our server counts visits without cookies or trackers. Your theme and your answer about ad measurement are remembered on this device.

Ad measurement

With your consent, our ad networks’ trackers (Google) measure our ads, from the visit to the sign-up and then to the first subscription and its amount, and may show you our ads. Your answer is valid for 13 months; you can change it here at any time.

No answer saved on this device.

After you decline, no tag is loaded anymore and the site deletes the cookies they had set on realmoon.ai. Those on the ad networks’ own domains are managed with them or in your browser.

The Moon AI app has its own privacy settings.