# GPT Image 2.5 in n8n: When the OpenAI Node Isn't Enough

> n8n's OpenAI node runs GPT Image 2.5 up to high quality and 1536 px but drops token usage. For xhigh, 4K, transparency or URL replies, use HTTP Request.

- URL: https://blog.laozhang.ai/en/posts/gpt-image-2-5-n8n
- Published: 2026-09-21
- Updated: 2026-09-25
- Author: LaoZhang AI Team (https://blog.laozhang.ai/en/about)
- Topic: AI Image Generation
- Tags: GPT Image 2.5, n8n, OpenAI API, Workflow Automation

---
**n8n's OpenAI node can call GPT Image 2.5 today: on node version 2.2 or later, switch the Model field to ID and enter `gpt-image-2.5-flare` or `gpt-image-2.5-sunburst`. The catch is what it can't send. Generate an Image stops at `high` quality and 1536 px, offers no transparent background or output format, and neither Generate nor Edit passes the token `usage` downstream.** If your workflow needs any of those, or your provider answers with a URL or a task ID instead of base64, build the request with the HTTP Request node instead.

## What each n8n path can send to GPT Image 2.5

"Node version" here means the `typeVersion` of the OpenAI node inside your workflow, not your n8n release. Copy the node (Ctrl+C or Cmd+C) and paste it into a text editor to see it. The model field accepts free-text IDs from version 2.2 for Generate and from version 2.3 for Edit; older node versions show a fixed list that ends at GPT Image 1.

| Setting | OpenAI node: Generate an Image | OpenAI node: Edit Image | HTTP Request |
| --- | --- | --- | --- |
| Model ID | From List or ID mode | From List or ID mode | Any string you send |
| Quality | `low`, `medium`, `high` (default `medium`) | `auto`, `high`, `medium`, `low` | `low` through `max`, plus `auto` |
| Size | `1024x1024`, `1024x1536`, `1536x1024` | The same three plus `auto` | Presets or custom up to 3840 px per edge |
| Transparent background | Not available | Background option | `background: "transparent"` with PNG or WebP |
| Output format | Not available (API default PNG) | Field shown, but see the note below | `png`, `jpeg`, `webp` and `output_compression` |
| Reference images | Not applicable | Several binary fields, sent as repeated `image[]` | Repeated `image[]` in Form-Data |
| Mask | Not applicable | Image Mask option | `mask` form field |
| Moderation strictness | Not available | Not available | `moderation: "low"` or `auto` |
| Token `usage` after the node | Dropped | Dropped | Full response body |
| URL or task-style responses | Not handled | Not handled | Handled with follow-up nodes |

The two OpenAI-node columns describe the node's source code on GitHub as of September 25, 2026. The newest release then was n8n 2.40.6, and the Generate operation's file hadn't changed since May 20, 2026. Installed versions can differ, so open **Add Option** on your own node and look at what Quality and Resolution actually offer.

Three details in the Edit column deserve a warning:

- The Size list also shows `256x256` and `512x512`. Both fall below GPT Image 2.5's minimum of 655,360 total pixels, so expect them to fail with 2.5.
- Quality also lists `Standard`, a DALL·E value. Leave it alone for 2.5.
- Output Format and Output Compression appear as regular fields, but the operation's code reads them from the Options collection, where they don't exist. As written, your choice may never reach the API, so a JPEG setting may still return a PNG. Check the MIME type of the returned binary before you rely on it.

**Use HTTP Request when you need any of these:** `xhigh`, `max` or `auto` quality on generation; 2K, 4K or custom sizes such as `1536x864`; a transparent background or JPEG/WebP output from a text prompt; per-image token records; `moderation: "low"`; or a provider that returns URLs or tasks. The native node is enough for `medium` or `high` images at 1K to 1536 px, and for edits with references and masks at those sizes, as long as you don't need cost records inside n8n.

## Setting up the native OpenAI node

The OpenAI credential has four fields that matter here: **API Key**, **Organization ID** (optional), **Base URL** (default `https://api.openai.com/v1`) and **Add Custom Header**. If you aren't sure whether to fill in the organization, [OpenAI API Key and Organization ID: What You Actually Need in 2026](https://blog.laozhang.ai/en/posts/openai-api-key-organization-id) walks through when it changes anything.

In the node, choose **Image → Generate an Image** or **Edit Image**, then set the model:

1. **From List** calls `/models` on whatever Base URL the credential points to and keeps IDs that contain `dall-e` or `gpt-image`. If the 2.5 models don't show up, that endpoint didn't list them.
2. **ID** accepts the exact string. Use `gpt-image-2.5-flare` or `gpt-image-2.5-sunburst`, or the dated snapshots `gpt-image-2.5-flare-2026-09-08` and `gpt-image-2.5-sunburst-2026-09-08` if you want the model pinned. There is no model called plain `gpt-image-2.5`.

If you're still choosing between the two, [GPT Image 2.5 Sunburst vs Flare: Which to Use, by the Numbers](https://blog.laozhang.ai/en/posts/gpt-image-2-5-sunburst-vs-flare) compares them on the tasks that differ.

The node decodes each returned image into a binary field, `data` by default (Generate lets you rename it with **Put Output in Field**; Edit always uses `data`). Point your upload node at that field. n8n's own documentation page for these operations still describes only DALL·E and GPT Image 1, so the field names in the node itself are the ones to follow.

For **Edit Image**, a few settings behave differently from what you might expect:

- **Images → Add Image** takes one binary field name per reference image. The node sends each one as `image[]`, and its field hint allows up to 16.
- A mask applies to the **first** image only. It must match that image's format and dimensions and contain an alpha channel. GPT Image treats the mask as guidance, so the edited area won't follow its outline exactly.
- The **Image Mask** option defaults to the field name `data`, the same default as the first image. Change it to the field that holds your mask, or the node will upload your photo as its own mask.
- Mask size limits differ by source: OpenAI's guide says image and mask must be under 50 MB, while the n8n field hint says the mask PNG must be under 4 MB. Keeping masks under 4 MB satisfies both.
- Leave **Input Fidelity** unset. OpenAI documents it only for earlier GPT Image models, and adding the option in n8n sends `low` by default.

## Building the HTTP Request version

The HTTP route takes a few more nodes, but every GPT Image 2.5 parameter becomes available and the response arrives intact, `usage` included.

![Two paths to an image file in n8n: the OpenAI node outputs a binary image that goes straight to upload, while HTTP Request returns JSON with base64 that Convert to File turns into a file, with a reminder to keep usage before conversion](https://blog.laozhang.ai/posts/en/gpt-image-2-5-n8n/img/binary-output-paths.webp)

### Generate an image

1. **Credential.** Create a Header Auth credential with Name `Authorization` and Value `Bearer ` followed by your API key.
2. **HTTP Request.** Method `POST`, URL `https://api.openai.com/v1/images/generations`. Turn on **Send Body**, pick **JSON**, choose **Using JSON**, and switch the field to Expression so it can read the incoming prompt:

```json
{
  "model": "gpt-image-2.5-flare",
  "prompt": {{ JSON.stringify($json.prompt) }},
  "size": "1536x864",
  "quality": "high",
  "output_format": "jpeg",
  "output_compression": 85
}
```

`JSON.stringify` keeps quotes and line breaks in a prompt from breaking the body. For a transparent product cutout, replace the last two lines with `"background": "transparent"` and `"output_format": "png"`. Don't send `response_format`: GPT Image models always return base64, and some OpenAI-compatible gateways reject the parameter outright.

If you start from an OpenAI curl example with **Import cURL**, n8n imports every value as a string, so `85` becomes `"85"`. Paste the body into **Using JSON** afterward to keep numbers as numbers.

3. **Edit Fields (Set).** Lift the image and the token counts into flat fields:

```text
image_b64      {{ $json.data[0].b64_json }}
input_tokens   {{ $json.usage.input_tokens }}
output_tokens  {{ $json.usage.output_tokens }}
total_tokens   {{ $json.usage.total_tokens }}
model          gpt-image-2.5-flare
```

If you turned on **Include Response Headers and Status** in the HTTP Request options, the response body moves under `body`, so the paths become `$json.body.data[0].b64_json` and `$json.body.usage.input_tokens`.

4. **Two branches from the Set node.** Connect one branch to wherever you record costs, such as an n8n Data Table or a Google Sheets row. Connect the other to **Convert to File**. The split matters because Convert to File outputs an item with empty JSON plus the file: anything you didn't save before it, including `usage`, is gone afterward.
5. **Convert to File.** Operation **Move Base64 String to File**, **Base64 Input Field** `image_b64`, **Put Output File in Field** `data`. Under Options, set **File Name** (for example `mug-{{ $now.toMillis() }}.jpg`) and **MIME Type** (`image/jpeg`, `image/png` or `image/webp`) to match the `output_format` you requested.
6. **Upload.** Point Google Drive, S3, email or any other destination node at the binary field `data`.

GPT Image 2.5 is billed by tokens, and identical token rates don't mean identical cost per image: model, size and quality change the count. The `usage` fields you saved in step 4 are the numbers to multiply. For the rates themselves and per-image estimates, see [GPT Image 2.5 Sunburst Pricing: Official Costs vs $0.03 per Call](https://blog.laozhang.ai/en/posts/gpt-image-2-5-api-pricing).

### Edit with reference images or a mask

Send `POST https://api.openai.com/v1/images/edits` with **Form-Data** as the body type:

| Parameter type | Name | Value or Input Data Field Name |
| --- | --- | --- |
| Form Data | `model` | `gpt-image-2.5-sunburst` |
| Form Data | `prompt` | Your edit instruction |
| n8n Binary File | `image[]` | The binary field holding the first image |
| n8n Binary File | `image[]` | A second reference, and so on |
| n8n Binary File | `mask` | The binary field holding the mask PNG (optional) |
| Form Data | `quality`, `size`, `background`, `output_format` | As needed |

The mask rules from the native section apply here too, and the mask targets the first `image[]` row.

## Match the chain to the response your endpoint returns

Changing the credential's Base URL is enough to point the native node at an OpenAI-compatible gateway, but only if that gateway accepts OpenAI's request format and returns clean `data[].b64_json`. The native node decodes that one field and nothing else. Anything different needs the HTTP route plus a follow-up step.

| What the response contains | How to spot it | Chain in n8n |
| --- | --- | --- |
| `data[].b64_json`, plain base64 | OpenAI's own Images API | Native node, or HTTP Request → Set → Convert to File |
| Base64 with a `data:image/png;base64,` prefix or missing `=` padding | The string starts with `data:`, or the saved file won't open | HTTP Request → Set with cleanup → Convert to File |
| `data[].url` that expires | A link instead of a long string | HTTP Request → second HTTP Request (GET the URL, Response Format **File**) → upload right away |
| A task ID with no image | The first reply has an ID and a status | HTTP Request (submit) → Wait → HTTP Request (poll) → If done → download |

For prefixed or unpadded base64, clean the string in the Set node before conversion. This expression strips the prefix, then adds back any missing `=`:

```text
image_b64  {{ (s => s.padEnd(Math.ceil(s.length / 4) * 4, '='))($json.data[0].b64_json.replace(/^data:image\/[a-z]+;base64,/, '')) }}
```

For task-style APIs, cap the loop. HiAPI's published n8n template, for example, checks every 5 seconds up to 36 times (about three minutes) and returns a `resultUrl`; saving the file is left to a separate step you add yourself.

One gateway that documents this behavior: [LaoZhang API's GPT Image 2.5 docs](https://docs.laozhang.ai/en/api-capabilities/gpt-image-2-5) use the Base URL `https://api.laozhang.ai/v1` with the same model IDs, `gpt-image-2.5-flare` and `gpt-image-2.5-sunburst`, billed by tokens at OpenAI's unit prices when the key is created in the `Sora2Official` group. The same docs say a response item can be either prefixed or unpadded base64 or an expiring `url`, so the HTTP route with the cleanup and download steps above is the safer build there. Its per-call models (`gpt-image-2.5-flare-vip` and `gpt-image-2.5-sunburst-vip`, $0.03 per call) don't accept a mask, and `gpt-image-2.5-web` doesn't let you choose between Flare and Sunburst.

*Disclosure: [laozhang.ai is our own service](https://blog.laozhang.ai/en/about#laozhang). Its prices are platform pricing, not an independent comparison.*

## Request spacing and timeouts for batch runs

OpenAI limits both GPT Image 2.5 models by images per minute (IPM) as well as tokens per minute. To stay under IPM with one image per request, space requests at least 60,000 ms ÷ IPM apart:

| OpenAI usage tier | Images per minute | Minimum spacing | Batch Interval to set |
| --- | --- | --- | --- |
| Tier 1 | 5 | 12,000 ms | 12000 |
| Tier 2 | 20 | 3,000 ms | 3000 |
| Tier 3 | 50 | 1,200 ms | 1200 |
| Tier 4 | 150 | 400 ms | 400 |
| Tier 5 | 250 | 240 ms | 240 |

In the HTTP Request node, open **Options → Batching** and set **Items per Batch** to `1` and **Batch Interval** to at least the value for your tier. The calculation assumes `n` = 1 and no other image traffic on the same organization; if other workflows share the key, raise the interval. At Tier 1, 100 product shots take at least 20 minutes (100 ÷ 5). Gateways set their own limits, so check your provider's numbers before reusing this table.

If you stay on the native OpenAI node, throttle it with **Loop Over Items** and a **Wait** node inside the loop.

OpenAI says complex prompts can take up to two minutes. The HTTP Request **Timeout** option (in milliseconds) controls how long n8n waits for the server to start responding, so set it well above that, for example `180000`, to avoid cutting off slow `xhigh` or `max` renders. A timeout in n8n doesn't prove nothing was generated. LaoZhang's docs state that a client timeout doesn't cancel generation on its side and a finished image is still billed; OpenAI's docs don't address that case. Check your usage or call log before you rerun a timed-out item.

## Which errors to retry and which to stop on

n8n's **Retry On Fail** setting retries every error the same way, which is wrong for image generation. Turn on **Never Error** (or route the node's error output) and branch on the error body instead. OpenAI recommends `error.code` as the stable field to branch on, and logging the request ID for support. With **Include Response Headers and Status** on, the `x-request-id` header is available to save alongside each item.

| What came back | What it means | What the workflow should do |
| --- | --- | --- |
| Rate-limit error | Too many requests or tokens this minute | Wait, then retry with a longer delay each time |
| Server error (5xx) | A transient failure on the provider's side | Retry with backoff, a few attempts at most |
| Quota error | Billing or credit limit reached | Stop and alert; retries can't succeed |
| `image_generation_user_error`, e.g. `moderation_blocked` | The prompt or input image needs changing | Send to review; log `moderation_details.moderation_stage` (`input`, `output` or `unknown`) |
| 403 or model not found | The organization may need API Organization Verification, or the ID is wrong | Complete [verification](https://help.openai.com/en/articles/10910291-api-organization-verification) in the developer console, then check the model ID |
| Parameter error about `response_format` | A DALL·E-era parameter was sent | Remove it from the body |

## Check each handoff before trusting the workflow

![Three checks for an n8n image workflow: the API response contains image data, the image file opens, and the destination confirms the upload](https://blog.laozhang.ai/posts/en/gpt-image-2-5-n8n/img/delivery-checks.webp)

A green execution only proves that every node returned something. Walk the chain in order and stop at the first check that fails:

1. **Does the response hold an image?** Look for `data[0].b64_json` or `data[0].url` in the HTTP output. If there's an `error` object instead, go to the error table above. If `data` is empty, save the full response and the request ID before trying again.
2. **Does the file open?** Download the binary from the Convert to File output. If it won't open, the base64 probably still has a `data:` prefix or lost its padding; use the cleanup expression. If it opens but the extension or MIME type is wrong, match File Name and MIME Type to the `output_format` you actually requested. For the native Edit node, check whether the format you picked was applied at all.
3. **Does it match the request?** Compare the pixel dimensions with the `size` you sent. OpenAI calls anything above `2560x1440` experimental, so check large outputs closely. If the image opens but looks noisy, [GPT Image 2.5 Grainy Noise: Fixes for ChatGPT and the API](https://blog.laozhang.ai/en/posts/gpt-image-2-5-noise-grainy) covers the usual causes.
4. **Did it arrive?** The upload node should return a file ID or link. Open that link, not the n8n preview, before you call the run finished.
5. **Was the cost recorded?** Confirm the usage row exists for the same item. If it's blank, the branch was connected after Convert to File or the response came from the native node.

## Common questions

### Why does n8n Insights show zero tokens for my image workflow?

The OpenAI node's image operations don't report token usage. GitHub issue [#38482](https://github.com/n8n-io/n8n/issues/38482) reproduces this with `gpt-image-2.5-flare` on n8n 2.38.6 and node version 2.3, and notes that `usage` can't be recovered with an expression or a Code node. The issue was still open as of September 25, 2026. Zero in Insights doesn't mean the images were free; switch to HTTP Request if you need the numbers.

### Can I generate 4K images from n8n?

Only through HTTP Request. GPT Image 2.5 accepts custom sizes whose edges are multiples of 16, up to 3840 px per edge, with an aspect ratio between 1:3 and 3:1 and 655,360 to 8,294,400 total pixels, so `3840x2160` qualifies. OpenAI labels everything above `2560x1440` experimental. For checking and saving outputs at that size, [GPT Image 2 4K API Guide: Generate, Save, and Verify 3840x2160 Images](https://blog.laozhang.ai/en/posts/gpt-image-2-4k-image-generation) applies the same steps to GPT Image 2.

### Does n8n need the Responses API for GPT Image 2.5?

No. Both 2.5 models work directly on `/v1/images/generations` and `/v1/images/edits`, which is what the OpenAI node and the HTTP setup above call. They can't be the top-level model of a Responses API request; there they only run as the model inside the image generation tool, which is a different setup from the one here.

## Sources

External pages this guide links to, in the order they appear. Last updated 2026-09-25.

- [verification](https://help.openai.com/en/articles/10910291-api-organization-verification) (help.openai.com)
- [#38482](https://github.com/n8n-io/n8n/issues/38482) (github.com)
