Theme
Language

Image generation (OpenAI Images API)

Synchronous image generation in the OpenAI Images API format: parameters, a wait of up to 300 seconds, billing only for a finished image, Cherry Studio setup. Editing goes through the async /api/media/generate.

POST /v1/images/generations generates images in the OpenAI Images API format: you send a request and get the image back in the same response. It is an adapter over the same queue as POST /api/media/generate: models, price, the balance check, supplier failover and the charge are shared, so the same generation costs the same on both addresses.

POSThttps://getvibeapi.com/v1/images/generations
curl https://getvibeapi.com/v1/images/generations \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"nano-banana","prompt":"a red bicycle on a bridge","n":1,"size":"1024x1024"}'

Response (HTTP 200):

{
  "created": 1792706400,
  "data": [{ "url": "https://getvibeapi.com/media/r/…/0.png" }]
}

Pass the key as Authorization: Bearer sk-pv-… or x-api-key. The official OpenAI SDK works as is:

from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key="sk-pv-...", timeout=600)
image = client.images.generate(model="nano-banana", prompt="a red bicycle on a bridge", size="1024x1024")
print(image.data[0].url)

Body parameters

ParameterTypeDescription
modelreq.stringAn image model id from /api/media-catalog (kind: "image"), e.g. nano-banana, gpt-image-2, flux-2. A vendor-prefixed id (google/nano-banana) and a pinned variant (gpt-image-2:network) are accepted too. Video and audio models are refused here with 400.
promptreq.stringDescription of the image.
nnumberOnly 1: each generation is a separate job with its own price. For several images, send several requests.
sizestringHonoured as an aspect ratio: 1024x1024 → 1:1, 1792x1024 → 16:9, 1024x1792 → 9:16, 1536x1024 → 3:2, 1024x1536 → 2:3; other values are reduced exactly (1920x1080 → 16:9). A ratio the model does not offer is refused with the list of supported sizes — there is no nearest-match substitution. "auto" or no field means the model default.
qualitystringOnly for models with a quality parameter in the catalog; an unsupported value is refused. "auto" omits it.
response_format"url" | "b64_json"url by default. b64_json returns the file in the response body (up to 20 MB).
userstringAccepted and ignored.

Unknown fields, and background, style, output_format, output_compression, moderation, stream and partial_images are refused with 400 by name rather than silently dropped — otherwise you would pay for an image you did not ask for. Models that need a source image (editing, upscaling, inpainting) do not work on this address, because there is no way to pass an image here; use POST /api/media/generate.

Waiting and timeout

The request is held open until the job finishes, for up to 300 seconds. The median time is 15 to 85 seconds depending on the model; individual generations on the slowest models take 3–4 minutes. Set your client timeout to at least 300 seconds (the OpenAI SDK default is 600).

  • Every response, including errors after the job was created, carries the x-pv-media-job-id header with the job id.
  • If the job did not finish within 300 seconds, the answer is 504 with cause: image_generation_timeout and the job id in the message. The generation keeps running: collect it from GET /api/media/jobs/{id}.
  • If the connection drops (app timeout, network), the job is still taken to completion. GET /v1/images/generations?limit=20 (up to 100) lists this key's recent images with their status, links and the charged amount cost_rub.

Billing

Nothing is charged at submission. Only a successfully completed generation is charged, at the same price as in /api/media-catalog and in the POST /api/media/price quote. A failed generation returns 502 saying "Nothing was charged" and costs nothing. The charged amount is returned in the x-pv-cost-rub header. If the balance cannot cover the generation, the answer is 402 before any job starts.

Links in data[].url point to our domain and live for 7 days after the generation completes, then answer 410 media_result_expired. Save the files on your side.

Errors

ParameterTypeDescription
400invalid_request_errorInvalid body: unknown_parameter, unsupported_parameter, unsupported_n, unsupported_size, unsupported_quality, unsupported_model_kind. Fix the request.
401 / 403authentication_error / permission_errorInvalid key, or the calling IP is not on the key allowlist.
402insufficient_quotaNot enough balance for this generation. No job was created.
404not_found_errormodel_not_found — no such image model. See /api/media-catalog.
429rate_limit_errorMedia rate limit; retry after Retry-After.
502upstream_errorThe generation failed. Nothing was charged; you can retry.
503upstream_errorThe model is unavailable at every supplier right now. No job was created; retry later or pick another model.
504upstream_errorimage_generation_timeout — the job is still running; collect it by the id from x-pv-media-job-id.

Desktop apps (Cherry Studio and others)

Any app that can generate images through an OpenAI-compatible provider works. Using Cherry Studio as the example:

  1. Add a provider of type OpenAI with the API address https://getvibeapi.com (the app appends /v1 itself) and your sk-pv-… key.
  2. Add the model by hand, using an id from https://getvibeapi.com/api/media-catalog (entries with kind: "image" only), e.g. nano-banana or gpt-image-2. The app's model list shows text models; media models are not in it.
  3. Generate from the app's painting / image generation feature, not from ordinary chat. Chat sends the request to /v1/chat/completions, where image models do not work.
  4. If the app lets you set a request timeout, set it to at least 300 seconds. An image the app gave up on is listed at GET /v1/images/generations. Retrying from the app creates a new generation that is charged separately.

The mode that edits an uploaded picture in such apps calls /v1/images/edits, which is served as well (see below).

Editing: /v1/images/edits

POST /v1/images/edits takes the OpenAI SDK request (multipart/form-data: the file in image, or several in image[], with prompt, model, size, quality and response_format) or JSON with images: [{"image_url": "…"}]. It works like generation above: the same response, the same wait, the same x-pv-media-job-id and the same price as POST /api/media/generate with a source image; a failed edit is not charged. The model's edit mode is picked from the catalog. A mask is refused with 400 unsupported_parameter, and a model that takes no source image with model_cannot_edit. For a masked edit use POST /api/media/generate and poll GET /api/media/jobs/{id} — see the async generation guide. Video is not generated synchronously: /v1/video/generations and /v1/videos answer 410 as well (details).

Nano Banana Pro id

In the catalog and new code use nano-banana-pro. For migrating existing async clients, the value gemini-3-pro-image is still accepted only in the model field of the /api/media/generate request and resolves to the same public model. It is not published in discovery or pricing.

GetVibe API image generation — OpenAI-compatible Images API | GetVibe API