Image generation is available for every project with no setup needed (user_pays billing by default).

Plan availability: Image generation is limited to 3 uses per month on the Free plan, then unlimited on Pro. When a Free-plan owner exceeds the cap, this endpoint returns 403 FORBIDDEN with an upgrade message - handle that response in the app's UI.

Capability boundary: text-to-image only

This service is text-to-image only: a text prompt in, a brand-new image out. The request has no input-image field - it cannot edit, restyle, inpaint, upscale, or make variations of an existing image, and there are no undocumented parameters that enable that. Don't guess at an image/input_image field; it doesn't exist.

If the app needs to modify an image the user already has, build that capability instead:

Use project_settings to customize (optional):

To make the billing choice reproducible (it ships with the app instead of living as out-of-band server state), declare it in a services deploy phase in gipity.yaml instead of only via project_settings - e.g. { service: image, billing_mode: owner_pays }. See deploy and app-llm.

Providers & Models

Quality tiers (recommended over pinning a model)

Instead of a concrete model id, pass a quality tier as model — it resolves to a current provider+model that we keep pointed at the best option, so your app keeps working when the model lineup refreshes (a pinned concrete id 400s the day it's retired). A tier sets the provider for you (overriding provider):

{ "prompt": "A sunset over mountains", "model": "high" }

GET /image/models returns the live tier→provider/model map (tiers) alongside the concrete model list. Pin a concrete id only when you specifically need that exact model.

Endpoints

Request Format (POST /image)

{
  "prompt": "A sunset over mountains",
  "provider": "openai",
  "model": "gpt-image-2",
  "size": "1024x1024",
  "quality": "auto"
}

Fields:

Response Format

{
  "url": "https://media.gipity.ai/med_abc12345.png",
  "content_type": "image/png",
  "revised_prompt": "...",
  "model": "gpt-image-2",
  "provider": "openai",
  "credits_used": 50
}

The url is a permanent public CDN URL. No auth needed to fetch it.

BFL responses also include a seed field — the seed that produced this image (the one you passed, or the random one BFL picked). Capture it and pass it back as seed on later calls to keep a series of images visually coherent.

CLI

For one-off image generation during development (downloads the result to a local file), skip the HTTP call and use gipity generate image. It writes to ./generated.png in the current directory by default - pass -o <path> to land the file directly in your source tree so it deploys:

gipity generate image "a cat wearing a top hat" -o src/assets/images/hat-cat.png
gipity generate image "landscape sunset" --provider gemini --aspect-ratio 16:9 -o src/assets/images/hero.png
gipity generate image "product photo" --provider openai --model gpt-image-2 --size 1536x1024 --quality high -o src/assets/images/product.png

Client Code Example

IMPORTANT: The token endpoint is on the API server. Use https://a.gipity.ai/api/token (POST).

// 1. Get app token
const tokenRes = await fetch('https://a.gipity.ai/api/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ app: '<PROJECT_GUID>' })
});
const { data: { token } } = await tokenRes.json();

// 2. Generate image
const res = await fetch('https://a.gipity.ai/api/<PROJECT_GUID>/services/image', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-App-Token': token },
  body: JSON.stringify({ prompt: 'A cat wearing a top hat' })
});
const data = await res.json();
// data.url → "https://media.gipity.ai/med_abc12345.png"

// 3. Display
const img = document.createElement('img');
img.src = data.url;
document.body.appendChild(img);

Limits