> ## Documentation Index
> Fetch the complete documentation index at: https://docs.globalai.vip/llms.txt
> Use this file to discover all available pages before exploring further.

# GPT Image

Global AI's image endpoints are OpenAI-compatible. Point `base_url` at the platform address, use your [token](/en/usage/tokens) as `api_key`, and your existing OpenAI SDK code runs without changing its structure.

## Before you start

<Steps>
  <Step title="Get a token">
    Go to [globalai.vip/keys](https://globalai.vip/keys) and copy a token that starts with `sk-`. If you do not have one, click **Create API key** to make one; see [Token management](/en/usage/tokens) for details.

    Tokens come in two groups that differ in the largest size they can produce. Pick by the **largest size you need**:

    | Group          | Sizes it can produce | Price  |
    | -------------- | -------------------- | ------ |
    | `gpt-image-2k` | 1K, 2K               | lower  |
    | `gpt-image-4k` | 1K, 2K, 4K           | higher |

    In short: if you never need 4K, `gpt-image-2k` is enough; for 4K you must use `gpt-image-4k` and pay a higher per-image price. For the exact models and pricing of each group, see the [model marketplace](https://globalai.vip/pricing).
  </Step>

  <Step title="Confirm the endpoints">
    Generation is `POST /v1/images/generations`, editing is `POST /v1/images/edits`. Both use the base URL `https://globalai.vip/v1`.
  </Step>

  <Step title="Install the SDK">
    Run `pip install openai` to install the official SDK, then point `base_url` at Global AI as shown below. Skip this step if you use the skill.
  </Step>

  <Step title="Pick a model and a size">
    Use `gpt-image-2.5-flare` (default) for speed, `gpt-image-2.5-sunburst` for quality and accurate text. Choose the size by the aspect ratio and resolution you need; see the next section.
  </Step>
</Steps>

Once that is done you have two options: the **Agent skill** (install once, then ask the AI in plain language) or the **HTTP API** (call the endpoints with the official SDK or curl). Pick one:

<CardGroup cols={2}>
  <Card title="Use the Agent skill (recommended)" icon="robot" href="#using-the-agent-skill">
    Install it once, then let the AI generate images for you without writing request code.
  </Card>

  <Card title="Call it with the OpenAI SDK" icon="code" href="#calling-it-with-the-openai-sdk">
    Call the endpoints directly with the official SDK or curl, so you can embed them in your own code.
  </Card>
</CardGroup>

## Models and sizes

| Model                    | Positioning                         | Best for                                       |
| ------------------------ | ----------------------------------- | ---------------------------------------------- |
| `gpt-image-2.5-flare`    | speed first (default)               | everyday illustrations, drafts, fast iteration |
| `gpt-image-2.5-sunburst` | quality first, accurate text layout | posters, covers, images containing text        |
| `gpt-image-2`            | previous mainstream model           | compatibility with older code                  |

Sizes fall into three groups by pixel count:

| Group | Sizes                                                                                                                                      |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| 1K    | `1024x1024`                                                                                                                                |
| 2K    | `1536x1024`, `1024x1536`, `1792x1024`, `1024x1792`, `2048x2048`, `2048x1152`, `1152x2048`, plus any other legal size at or below 2560x1440 |
| 4K    | `3840x2160`, `2160x3840`, plus any other legal size above 2560x1440                                                                        |

Any other legal size must satisfy all of these, otherwise the request fails:

* width and height are both **multiples of 16**
* the longest edge is at most **3840**
* the long-to-short ratio is at most **3:1**
* total pixels are between **655,360 and 8,294,400**

<Note>
  Fallback: an empty, `auto`, or malformed `size` is treated as 2K. The group decides billing and routing, and the model decides the actual output size; the `size` field in the response only echoes what you requested, so read `width` / `height` or the image file itself for the real dimensions.
</Note>

Measured latency and file size for common sizes:

| Size        | Group | Ratio | Time per image | Size per image |
| ----------- | ----- | ----- | -------------- | -------------- |
| `1024x1024` | 1K    | 1:1   | \~30-40 s      | \~2.5 MB       |
| `1152x2048` | 2K    | 9:16  | \~45-50 s      | \~6 MB         |
| `2160x3840` | 4K    | 9:16  | \~60-110 s     | \~13 MB        |
| `3840x2160` | 4K    | 16:9  | \~60-110 s     | \~13 MB        |

<Note>
  Each step up in size or quality noticeably increases both latency and quota usage. Get your flow working with `1024x1024` + `low` first, then switch to the target size.
</Note>

## Using the Agent skill

The skill is a `SKILL.md` plus a script. Install it once, then just tell the AI "use globalai to generate a 2K portrait illustration" - no request code to write. It works in Codex, Claude Code, and Hermes.

### Download

[**https://static.globalai.vip/skill/gpt-image/globalai-image-gen-skill.zip**](https://static.globalai.vip/skill/gpt-image/globalai-image-gen-skill.zip)

### Where to put it

Put the extracted `globalai-image-gen/` folder in the matching location:

| Tool         | Location                                                                        |
| ------------ | ------------------------------------------------------------------------------- |
| Codex        | `~/.codex/skills/` (Windows: `%USERPROFILE%\.codex\skills`)                     |
| Claude Code  | `~/.claude/skills/` (Windows: `%USERPROFILE%\.claude\skills`)                   |
| Hermes Agent | `~/.hermes/skills/creative/` (Windows: `%USERPROFILE%\.hermes\skills\creative`) |

<Note>
  Restart the client once after placing it, so the skill gets loaded.
</Note>

### Configure the key

The skill needs a single key, `GLOBALAI_API_KEY`. Set it as an environment variable for your platform:

| Platform             | How to set it                                                                                                                                              |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Linux                | `echo 'export GLOBALAI_API_KEY=sk-xxxxxxxx' >> ~/.bashrc && source ~/.bashrc`                                                                              |
| macOS                | `echo 'export GLOBALAI_API_KEY=sk-xxxxxxxx' >> ~/.zshrc && source ~/.zshrc`                                                                                |
| Windows (PowerShell) | `setx GLOBALAI_API_KEY "sk-xxxxxxxx"` (persists; the skill reads the registry directly so it takes effect right away, other tools may need a new terminal) |

If you would rather not touch environment variables, save the key into the skill's own private config:

```bash Save the key to the theme={null}
python3 ~/.codex/skills/globalai-image-gen/scripts/generate_image.py --save-api-key "sk-xxxxxxxx"
```

Keys are resolved in this order: the `--api-key` argument, then the `GLOBALAI_API_KEY` / `GLOBALAI_IMAGE_API_KEY` environment variables, then the skill's private config file. That file belongs to this skill alone and never reads or writes `OPENAI_API_KEY`. To see where the key is stored, or to delete it:

```bash Inspect and clear the config icon=terminal theme={null}
python3 ~/.codex/skills/globalai-image-gen/scripts/generate_image.py --show-config-path
python3 ~/.codex/skills/globalai-image-gen/scripts/generate_image.py --clear-api-key
```

### Usage

Ask the agent directly:

```text Tell the agent theme={null}
Use globalai to generate a 2K portrait illustration of an otter under the stars
```

Or run the script yourself:

```bash Generate an image icon=terminal theme={null}
python3 ~/.codex/skills/globalai-image-gen/scripts/generate_image.py \
  --prompt "An otter wearing a scarf" \
  --model gpt-image-2.5-sunburst --size 1152x2048 --quality high --out out.png
```

```bash Edit an image icon=terminal theme={null}
python3 ~/.codex/skills/globalai-image-gen/scripts/generate_image.py --mode edit \
  --image input.png \
  --prompt "Change the background to a snowy mountain sunset" \
  --size 1024x1024 --quality high --out edited.png
```

Common arguments:

| Argument             | Meaning                                                                                           |
| -------------------- | ------------------------------------------------------------------------------------------------- |
| `--model`            | defaults to `gpt-image-2.5-flare`; also takes `gpt-image-2.5-sunburst` or `gpt-image-2`           |
| `--size`             | defaults to `1024x1024`; takes `auto` or any legal size from the table above                      |
| `--quality`          | defaults to `low`; pass `high` or above for images you will actually use                          |
| `--out` / `--output` | output file path; the two names are equivalent                                                    |
| `--mode edit`        | use the edit endpoint, with `--image` (repeatable) and the optional `--mask`                      |
| `--list-models`      | list the models this key can use; run it when unsure about a model id                             |
| `--output-format`    | defaults to `png`, also takes `jpeg` / `webp`                                                     |
| `--n`                | number of images, default 1; the current models return one image per call, so call again for more |

The shortcuts `--save-api-key` / `--show-config-path` / `--clear-api-key` manage the key, while `--api-key` and `--base-url` temporarily override the defaults. The script uses only the Python standard library, so it runs without installing the `openai` package.

> The script path above uses Codex as the example; for another tool, replace `~/.codex/skills/` with the matching location from the table. On Windows use `python` instead of `python3` and paths such as `%USERPROFILE%\.codex\skills\`.

<Note>
  The script only accepts `b64_json`: it writes the base64 payload to disk, and stops with an explicit error when the response carries only a `url`, instead of depending on an expiring temporary link. If your size and model combination only ever returns `url`, use the SDK or curl path below and download the image as described in Response format.
</Note>

## Calling it with the OpenAI SDK

```bash Install the SDK icon=terminal theme={null}
pip install openai
```

### Generate an image

```python image_gen.py icon=python theme={null}
from openai import OpenAI
import base64

client = OpenAI(
    api_key="sk-xxxxxxxx",
    base_url="https://globalai.vip/v1",
)

resp = client.images.generate(
    model="gpt-image-2.5-sunburst",
    prompt="An otter wearing a scarf, flat illustration style",
    size="1152x2048",
    quality="high",
    extra_body={"response_format": "b64_json"},
)

item = resp.data[0]
img = base64.b64decode(item.b64_json)

open("out.png", "wb").write(img)
print(f"saved {len(img) / 1e6:.2f} MB")
```

<Warning>
  Always send `response_format: "b64_json"`. Without it the gateway may return the image as a pre-signed `url` and leave `b64_json` empty; that link expires, so saving the link is useless. The SDK only validates known parameters, which is why `response_format` goes through `extra_body`.
</Warning>

If the channel still returns only a `url` (`item.b64_json` is empty), the image is still reachable - you just have to download it instead of storing the link:

```python Handle both response shapes icon=python theme={null}
import base64
import urllib.request

item = resp.data[0]

if item.b64_json:
    img = base64.b64decode(item.b64_json)
else:
    with urllib.request.urlopen(item.url, timeout=300) as r:
        img = r.read()

open("out.png", "wb").write(img)
```

### Edit an image

The edit endpoint `POST /v1/images/edits` takes an input image and modifies it according to the prompt. Pass a `mask` to control which part changes: the **transparent** areas of the mask are repainted, the opaque areas stay untouched. Inputs and masks accept PNG, JPEG, and WebP.

```python image_edit.py icon=python theme={null}
from openai import OpenAI
import base64

client = OpenAI(
    api_key="sk-xxxxxxxx",
    base_url="https://globalai.vip/v1",
)

resp = client.images.edit(
    model="gpt-image-2.5-flare",
    image=open("input.png", "rb"),
    prompt="Change the background to a snowy mountain sunset",
    size="1024x1024",
    quality="high",
    extra_body={"response_format": "b64_json"},
)

item = resp.data[0]
img = base64.b64decode(item.b64_json)

open("edited.png", "wb").write(img)
```

<Warning>
  The mask must match the input dimensions. To edit only a small area, build a same-size PNG that is transparent exactly where the edit should happen and opaque everywhere else. To send several input images, repeat the `image` argument.
</Warning>

### Request parameters

Generation:

| Parameter         | Required | Notes                                                                                                                                                 |
| ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`           | yes      | `gpt-image-2.5-flare` / `gpt-image-2.5-sunburst` / `gpt-image-2`                                                                                      |
| `prompt`          | yes      | the prompt; any language works                                                                                                                        |
| `size`            | no       | see the size groups in Models and sizes; empty or `auto` is treated as 2K                                                                             |
| `quality`         | no       | `auto` / `low` / `medium` / `high` / `xhigh` / `max`; `xhigh` and `max` are available on 2.5-series models only                                       |
| `response_format` | no       | pass `b64_json` to reliably receive base64; without it the response may carry only a `url`                                                            |
| `output_format`   | no       | `png` (default) / `jpeg` / `webp`                                                                                                                     |
| `n`               | no       | number of images, currently 1; issue several requests concurrently for more                                                                           |
| `background`      | no       | background handling, echoed in the response; transparent backgrounds require `output_format` to be `png` or `webp`, and not every model supports them |
| `moderation`      | no       | moderation level, echoed in the response, defaults to `auto`                                                                                          |

Edit:

| Parameter         | Required | Notes                                                                                  |
| ----------------- | -------- | -------------------------------------------------------------------------------------- |
| `model`           | yes      | same as generation                                                                     |
| `image`           | yes      | the image to edit, PNG / JPEG / WebP; repeat the field for multiple inputs             |
| `prompt`          | yes      | describes the change                                                                   |
| `mask`            | no       | the region to edit; transparent areas are repainted, and the size must match the input |
| `size`            | no       | output size, same rules as generation                                                  |
| `quality`         | no       | same as generation                                                                     |
| `response_format` | no       | same as generation; passing `b64_json` is recommended                                  |

### Response format

The image can come back in one of two shapes, depending on which upstream channel this request took. Check `b64_json` first, and fall back to `url`.

#### Case 1: b64\_json (recommended)

Send `response_format: "b64_json"` and the response carries the base64-encoded PNG directly; decode it and write the file:

```json Response (b64_json) theme={null}
{
  "created": 1789010323,
  "model": "gpt-image-2.5-flare",
  "size": "1152x2048",              // echoes the request
  "quality": "high",                // echoes the request
  "output_format": "png",
  "background": "auto",
  "moderation": "auto",
  "data": [
    {
      "b64_json": "iVBORw0KGgo...",   // base64-encoded PNG
      "width": 1152,                  // actual output width (returned by some channels)
      "height": 2048,                 // actual output height (returned by some channels)
      "revised_prompt": "..."         // the prompt the model actually used (some channels only)
    }
  ],
  "usage": {
    "input_tokens": 14,
    "output_tokens": 974,
    "total_tokens": 988
  }
}
```

`revised_prompt` is the prompt the model actually used - when the result does not match your intent, compare against it to check whether the prompt was rewritten. `usage` shows that `output_tokens` (image tokens) is what consumes quota; see [Usage logs](/en/usage/logs) for per-request accounting.

<Note>
  The base64 of a 4K image is roughly a third larger than the file itself. Do not print it to the terminal - write it to disk and process it from there.
</Note>

#### Case 2: url

The same model and the same key can also return the image as a `url` instead of `b64_json`. That depends on the upstream channel behind this size and model, and does not mean your request was wrong:

```json Response (url) theme={null}
{
  "created": 1789010323,
  "model": "gpt-image-2.5-flare",
  "size": "1024x1024",
  "quality": "low",
  "output_format": "png",
  "background": "auto",
  "moderation": "auto",
  "data": [
    {
      "url": "https://<object-storage-host>/images/<id>?X-Amz-Algorithm=...&X-Amz-Expires=..."
    }
  ],
  "usage": { "input_tokens": 14, "output_tokens": 974, "total_tokens": 988 }
}
```

That `url` is a **pre-signed link**: it carries temporary credentials and **expires**, after which the image cannot be fetched at all. So:

* **Download and save it immediately**. Do not store the link in a database and do not hand it to an end user as the result.
* Do not design a flow that "returns the link now and downloads later" - once the validity window passes, the image is gone.
* A single response never contains both forms; branch on whether `b64_json` exists.

<Warning>
  A `url` is a way to fetch the image, not the image itself. Replacing "save the file" with "save the link" only produces results that will not open.
</Warning>

### Concurrency and retries

* **Retry these**: `429`, `500`, `502`, `503`, `504`.
* **Do not retry**: `400`, `401`, `403`, and insufficient quota - retrying only wastes time.
* **Recommended backoff**: wait 2 seconds after the first failure, 4 seconds after the second, and stop after 3 attempts.
* **Give the client enough time**: a single 4K image takes 60-110 seconds, so set the HTTP timeout to 300 seconds or more, otherwise you will cut off healthy requests.
* **Concurrency guidance**: 1-2 parallel 4K requests is a safe level; for batches, run one batch to completion before starting the next rather than saturating the limit at once.
* The OpenAI SDK retries by default (`max_retries=2`) and only covers 5xx; wrap `429` and connection errors yourself.

### Using curl without the SDK

```bash Generate an image icon=terminal theme={null}
curl https://globalai.vip/v1/images/generations \
  -H "Authorization: Bearer sk-xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2.5-sunburst",
    "prompt": "An otter wearing a scarf, flat illustration style",
    "size": "1152x2048",
    "quality": "high",
    "response_format": "b64_json"
  }' -o resp.json
```

```bash Decode the PNG (handles b64_json and url) icon=terminal theme={null}
python3 -c "
import base64, json, urllib.request
item = json.load(open('resp.json'))['data'][0]
data = base64.b64decode(item['b64_json']) if item.get('b64_json') else urllib.request.urlopen(item['url'], timeout=300).read()
open('out.png', 'wb').write(data)
print('saved', len(data), 'bytes')
"
```

```bash Edit an image icon=terminal theme={null}
curl https://globalai.vip/v1/images/edits \
  -H "Authorization: Bearer sk-xxxxxxxx" \
  -F model=gpt-image-2.5-flare \
  -F image=@input.png \
  -F prompt="Change the background to a snowy mountain sunset" \
  -F size=1024x1024 \
  -F response_format=b64_json \
  -o resp.json
```

<Note>
  The edit endpoint is `multipart/form-data`, so curl passes files with `-F`, while the generation endpoint takes JSON through `-d`. The `b64_json` in the response is base64 text; only decoding it yields a PNG.
</Note>

## Common errors

<AccordionGroup>
  <Accordion title="401 invalid api key / insufficient quota">
    The token is wrong, expired, or deleted; check its status in [Token management](/en/usage/tokens). If the message says the quota is used up, top it up in [Quota and top-up](/en/billing/topup) or raise the token's quota limit. Neither case will succeed by retrying.
  </Accordion>

  <Accordion title="400: bad model, size, or parameter">
    The model id is misspelled, or the token is not allowed to use that model - check with `GET https://globalai.vip/v1/models`. The size has to satisfy the legal range from Models and sizes: both edges multiples of 16, longest edge at most 3840, ratio at most 3:1, total pixels between 655,360 and 8,294,400, and never `1K`, `2K`, or `4K` as the value itself. `quality` may be a level the model does not support, since `xhigh` and `max` are 2.5-series only. On the edit endpoint, confirm `image` is PNG, JPEG, or WebP and that the `mask` matches the input dimensions. The request itself is wrong, so retrying will not help.
  </Accordion>

  <Accordion title="429 / 502 / 503: rate limits and upstream hiccups">
    `429` means too many requests or too much concurrency in a short window: back off by 2 seconds, then 4, and lower the concurrency. `502` means the upstream is flaky and usually succeeds when retried as-is. `503` (`model_not_found`) means no channel is available for the model group behind that size: try another size, or contact support to add capacity. Connection timeouts behave the same way - raise the client timeout to 300 seconds or more first; retrying after a timeout is safe but may be billed twice.
  </Accordion>

  <Accordion title="The response carries a url instead of b64_json">
    This is not an error: it means this channel put the image into a pre-signed `url`. The two forms never appear together, so just branch on whether `b64_json` exists. The `url` expires, so download it to disk immediately instead of storing the link. The skill script stops with an error in this case - switch to the SDK or curl path and handle it as described in Response format.
  </Accordion>

  <Accordion title="The saved image will not open">
    `b64_json` is a base64-encoded PNG, so decode it with `base64.b64decode` before writing the file; writing the text as-is produces a corrupt file. With curl, save the response to `resp.json` first and decode afterwards, rather than redirecting the response straight into a `.png`.
  </Accordion>
</AccordionGroup>
