GPT Image 2
Generate and edit images with gpt-image-2 through the OpenAI-compatible BeansAI API.
Overview
Use the same BeansAI key and base URL as chat models. Text-to-image goes to POST /images/generations; reference-image edits go to POST /images/edits.
Most image upstream nodes support streaming. Add stream: true to production image calls so proxies receive progress events instead of waiting for one large response.
Text to image
curl https://api.beansai.dev/v1/images/generations \
-N \
-H "Authorization: Bearer sk-beans-..." \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A clean product photo of a green coffee bean mascot on a white background",
"size": "1024x1024",
"quality": "high",
"n": 1,
"response_format": "b64_json",
"stream": true
}'Reference image edit
Send reference images as data URLs in images[].image_url. PNG, JPEG, and WebP inputs are the safest choices.
IMAGE_B64="$(base64 -i reference.png | tr -d '\n')"
curl https://api.beansai.dev/v1/images/edits \
-N \
-H "Authorization: Bearer sk-beans-..." \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"gpt-image-2\",
\"prompt\": \"Keep the same product, place it on a polished studio desk\",
\"images\": [{ \"image_url\": \"data:image/png;base64,$IMAGE_B64\" }],
\"size\": \"1024x1024\",
\"quality\": \"high\",
\"response_format\": \"b64_json\",
\"stream\": true
}"Streaming
curl https://api.beansai.dev/v1/images/generations \
-N \
-H "Authorization: Bearer sk-beans-..." \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A cinematic poster for an AI API gateway called BeansAI",
"size": "2016x1344",
"quality": "high",
"response_format": "b64_json",
"stream": true
}'Streamed responses are SSE. Read *.partial_image for previews when available, then read *.completed and decode the b64_json image payload.
Pricing tiers
BeansAI charges gpt-image-2 by preset size and quality tier, not by a single flat image price. The request is normalized to one of the supported preset sizes below; unsupported custom sizes are rejected.
| Preset size | low | medium | high |
|---|---|---|---|
| 1024x1024 | $0.0059 | $0.0527 | $0.2107 |
| 1024x768 | $0.0040 | $0.0361 | $0.1445 |
| 1008x672 | $0.0035 | $0.0309 | $0.1234 |
| 1088x608 | $0.0029 | $0.0259 | $0.1035 |
| 1440x480 | $0.0016 | $0.0155 | $0.0620 |
| 768x1024 | $0.0040 | $0.0361 | $0.1445 |
| 672x1008 | $0.0035 | $0.0309 | $0.1234 |
| 608x1088 | $0.0029 | $0.0259 | $0.1035 |
| 480x1440 | $0.0016 | $0.0155 | $0.0620 |
| 2048x2048 | $0.0119 | $0.1070 | $0.4282 |
| 2048x1536 | $0.0074 | $0.0667 | $0.2668 |
| 2016x1344 | $0.0062 | $0.0543 | $0.2170 |
| 2048x1152 | $0.0047 | $0.0424 | $0.1695 |
| 2784x928 | $0.0028 | $0.0264 | $0.1056 |
| 1536x2048 | $0.0074 | $0.0667 | $0.2668 |
| 1344x2016 | $0.0062 | $0.0543 | $0.2170 |
| 1152x2048 | $0.0047 | $0.0424 | $0.1695 |
| 928x2784 | $0.0028 | $0.0264 | $0.1056 |
| 2880x2880 | $0.0198 | $0.1779 | $0.7116 |
| 2880x2160 | $0.0119 | $0.1066 | $0.4262 |
| 3456x2304 | $0.0132 | $0.1148 | $0.4591 |
| 3840x2160 | $0.0111 | $0.1001 | $0.4003 |
| 3840x1280 | $0.0042 | $0.0398 | $0.1593 |
| 2160x2880 | $0.0119 | $0.1066 | $0.4262 |
| 2304x3456 | $0.0132 | $0.1148 | $0.4591 |
| 2160x3840 | $0.0111 | $0.1001 | $0.4003 |
| 1280x3840 | $0.0042 | $0.0398 | $0.1593 |
Python
import base64
import json
import requests
res = requests.post(
"https://api.beansai.dev/v1/images/generations",
headers={
"Authorization": "Bearer sk-beans-...",
"Accept": "text/event-stream",
},
json={
"model": "gpt-image-2",
"prompt": "A minimal green coffee bean logo on a white background",
"size": "1024x1024",
"quality": "high",
"response_format": "b64_json",
"stream": True,
},
stream=True,
timeout=600,
)
res.raise_for_status()
image_b64 = None
for line in res.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
payload = line[5:].strip()
if payload == "[DONE]":
break
event = json.loads(payload)
if str(event.get("type", "")).endswith(".completed"):
image_b64 = event.get("b64_json")
break
if not image_b64:
raise RuntimeError("No completed image event returned")
with open("beansai-image.png", "wb") as f:
f.write(base64.b64decode(image_b64))JavaScript
import fs from "node:fs";
const res = await fetch("https://api.beansai.dev/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer sk-beans-...",
Accept: "text/event-stream",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2",
prompt: "A friendly AI dashboard illustration with green accents",
size: "1024x1024",
quality: "high",
response_format: "b64_json",
stream: true,
}),
});
if (!res.ok) throw new Error(await res.text());
if (!res.body) throw new Error("No response body");
const decoder = new TextDecoder();
const reader = res.body.getReader();
let buffer = "";
let image = "";
function processBlock(block) {
const data = block
.split(/\r?\n/)
.filter((line) => line.startsWith("data:"))
.map((line) => line.slice(5).trimStart())
.join("\n")
.trim();
if (!data || data === "[DONE]") return;
const event = JSON.parse(data);
if (String(event.type || "").endsWith(".completed")) {
image = event.b64_json || "";
}
}
while (!image) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const blocks = buffer.split(/\r?\n\r?\n/);
buffer = blocks.pop() || "";
for (const block of blocks) processBlock(block);
}
if (!image && buffer.trim()) processBlock(buffer);
if (!image) throw new Error("No completed image event returned");
fs.writeFileSync("beansai-image.png", Buffer.from(image, "base64"));Tips
- Use
response_format: "b64_json"when you want to save the image yourself. - Common sizes are
1024x1024,2048x1152, and3840x2160. Use the dashboard Playground when you want to test a prompt visually first. - Add
stream: trueby default for image integrations. It reduces idle proxy timeouts and still returns the final image in a completed SSE event.