API генерации изображений
Генерируйте изображения по текстовому запросу через GPT Image и OpenAI-совместимый API BetterToken. Описаны API Key, Base URL, параметры, примеры, оплата и ошибки.
POST /v1/images/generations
Endpoint text-to-image использует тело запроса application/json. Передайте prompt, держите HTTP-запрос открытым и обработайте все изображения из data[].b64_json в том же ответе.
Выберите нужный сценарий
- Сгенерировать изображение из текста и сохранить результат: оставайтесь на этой странице. Начните с примера
curl, затем в разделе Сохранение изображения декодируйте каждый элементdata[]. - Отредактировать изображение: загрузите одну или несколько референсных картинок через API редактирования изображений. Для обычного редактирования mask не нужна; добавьте её только для локального редактирования, если выбранные модель и размер поддерживают эту операцию.
- Выбрать модель, параметры и оценить бюджет: проверьте доступные Model ID и цены в model plaza. Полный рабочий процесс описан в руководстве GPT Image 2.
Быстрый старт с curl
Используйте https://bettertoken.ai/v1 как Base URL и отправьте запрос на https://bettertoken.ai/v1/images/generations:
curl --max-time 300 -X POST "https://bettertoken.ai/v1/images/generations" \ -o response.json \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "A product photo of a green ceramic mug on a studio table", "size": "1024x1024", "n": 1, "response_format": "b64_json", "output_format": "png" }'Рекомендуемые значения
Это рекомендуемые начальные значения, а не фиксированные требования. Рекомендуется n=1; endpoint принимает целое число от 1 до 10, но может вернуть меньше изображений.
{ "model": "gpt-image-2", "n": 1, "response_format": "b64_json", "output_format": "png"}| Параметр | Что передавать | Назначение |
|---|---|---|
model | gpt-image-2, gpt-image-2.5-flare или gpt-image-2.5-sunburst | Выберите Model ID, доступный в model plaza. Допустимый ID не гарантирует доступность модели, размера или операции для конкретного запроса. |
prompt | Текстовое описание | Обязательное описание изображения. Укажите объект, стиль, композицию и важные ограничения. |
size | Пропустите, укажите auto или задайте размеры, например 1024x1024 | Запрошенный размер и соотношение сторон; фактические размеры могут отличаться. |
n | Целое число от 1 до 10 | Максимум изображений в запросе. Начните с 1; ответ может содержать меньше изображений. |
quality | auto, low, medium, high для gpt-image-2; две модели 2.5 также принимают xhigh и max | Необязательное предпочтение качества. Пропустите поле или передайте JSON null, чтобы использовать значение по умолчанию. Приём параметра не гарантирует улучшение изображения при повышении уровня. |
response_format | b64_json | Возвращает каждое изображение в base64 в data[].b64_json. |
output_format | Например, png | Запрашивает формат, но не гарантирует соответствующую кодировку файла. Перед сохранением определите фактический формат по байтам. |
Ответ может содержать меньше изображений, чем n. Обрабатывайте каждый элемент data[]; рекомендация использовать n=1 не является серверным ограничением.
Рекомендуемые размеры
size | Соотношение | Сценарий |
|---|---|---|
auto | Auto | Автоматический выбор размера |
1024x1024 | 1:1 | Квадратные изображения, аватары, обложки, assets |
1536x1024 | 3:2 | Landscape-постеры, баннеры, сцены |
1024x1536 | 2:3 | Portrait-обложки для мобильных и постеры |
1536x1152 | 4:3 | Стандартные landscape-изображения, product images, content graphics |
1152x1536 | 3:4 | Стандартные portrait-изображения, mobile covers, vertical posters |
2048x2048 | 1:1 | High-resolution квадратные изображения |
2048x1152 | 16:9 | High-resolution landscape-изображения |
3840x2160 | 16:9 | 4K landscape-изображения |
2160x3840 | 9:16 | 4K portrait-изображения |
Таблица содержит примеры, а не закрытый список. size можно пропустить или задать как auto; null в JSON включает автоматический выбор. Явные ширина и высота должны быть положительными кратными 16, каждая не больше 3840; соотношение сторон не должно превышать 3:1, а число пикселей должно быть от 655360 до 8294400. Например, 2080x2080 допустим. Фактический размер может отличаться от запрошенного, поэтому проверяйте размер изображения и не обрезайте его принудительно.
Сохранение изображения
Успешный ответ следует OpenAI-совместимой форме image response. Суммы ниже показывают формат квитанции и не являются фиксированными ценами:
{ "created": 1710000000, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)", "revised_prompt": "Optional revised prompt" } ], "bettertoken_image_billing": { "currency": "CNY", "settled_amount": "0.15", "outputs": [ { "index": 0, "width": 1254, "height": 1254, "billing_resolution": "2K", "currency": "CNY", "amount": "0.15" } ] }}Прочитайте все data[].b64_json и разрешайте дополнительные поля, например revised_prompt. BetterToken возвращает расчёт в корневом объекте bettertoken_image_billing: суммы settled_amount и amount являются decimal strings, а outputs[].index начинается с 0. Фактические размеры и billing_resolution в этом объекте описывают завершённый расчёт.
output_format — запрос формата, а не гарантия кодирования или конвертации. Определяйте формат по байтам и используйте соответствующее расширение. Приведённые примеры распознают PNG, JPEG и WebP без дополнительных зависимостей.
import base64import jsonfrom pathlib import Path
result = json.loads(Path("response.json").read_text(encoding="utf-8"))for index, item in enumerate(result["data"], start=1): encoded = item["b64_json"] if "," in encoded and "base64" in encoded.split(",", 1)[0]: encoded = encoded.split(",", 1)[1] image_bytes = base64.b64decode(encoded) if image_bytes.startswith(b"\x89PNG\r\n\x1a\n"): extension = "png" elif image_bytes.startswith(b"\xff\xd8\xff"): extension = "jpg" elif image_bytes.startswith(b"RIFF") and image_bytes[8:12] == b"WEBP": extension = "webp" else: raise ValueError("Unsupported image signature") Path(f"output-{index}.{extension}").write_bytes(image_bytes)Пример JavaScript (Node.js)
import { writeFile } from "node:fs/promises";
const response = await fetch("https://bettertoken.ai/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-image-2", prompt: "A green ceramic mug on a studio table", size: "1024x1024", n: 1, response_format: "b64_json", output_format: "png", }),});
if (!response.ok) { throw new Error(await response.text());}
const result = await response.json();const { data } = result;for (const [index, item] of data.entries()) { const b64Json = item.b64_json.replace(/^data:.*;base64,/, ""); const imageBytes = Buffer.from(b64Json, "base64"); let extension; if (imageBytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) { extension = "png"; } else if (imageBytes[0] === 0xff && imageBytes[1] === 0xd8 && imageBytes[2] === 0xff) { extension = "jpg"; } else if (imageBytes.toString("ascii", 0, 4) === "RIFF" && imageBytes.toString("ascii", 8, 12) === "WEBP") { extension = "webp"; } else { throw new Error("Unsupported image signature"); } await writeFile(`output-${index + 1}.${extension}`, imageBytes);}Если приложению нужна фиксированная кодировка PNG, JPEG или WebP, сначала определите фактический формат, затем при необходимости перекодируйте изображение. Изменение расширения файла само по себе не преобразует изображение.
Фактическая стоимость
bettertoken_image_billing возвращается в том же ответе; отдельный запрос стоимости не нужен.
| Поле | Значение |
|---|---|
currency | Валюта расчёта; это не обязательно USD или CNY. |
settled_amount | Итоговая сумма запроса в виде десятичной строки. |
requested_resolution | Уровень разрешения, определённый по запросу. |
outputs[].index | Индекс с нуля, соответствующий изображению в data[]. |
outputs[].width, height | Фактические размеры изображения в пикселях. |
outputs[].billing_resolution | Итоговый тарифный уровень изображения. |
outputs[].currency, amount | Валюта и сумма расчёта за изображение. |
Размер запроса и тарифный уровень могут различаться: запрос 1024x1024 возвращал 1254x1254 с тарификацией 2K. Используйте сумму из квитанции; текущие цены указаны на модельной площадке. Для отображения сохраняйте суммы строками, для вычислений используйте десятичную арифметику. Отсутствующая квитанция не означает нулевую стоимость.
from decimal import Decimal
billing = result.get("bettertoken_image_billing")if billing is None: print("Billing receipt unavailable; check your usage records.")else: total = Decimal(billing["settled_amount"]) print(f"Total: {billing['currency']} {total}") for output in billing.get("outputs", []): print( f"Image {output['index'] + 1}: " f"{output['width']}x{output['height']}, " f"{output['billing_resolution']}, " f"{output['currency']} {output['amount']}" )Поток ответа
Endpoint синхронный. После отправки POST /images/generations держите HTTP-запрос открытым до ответа сервера. При успехе каждое изображение возвращается в data[].b64_json со сведениями о доставке и расчёте.
Endpoint не возвращает task_id; отдельного status query или endpoint для скачивания результата нет.
Тайм-ауты, повторные запросы и списания
Задайте timeout HTTP-клиента в несколько минут. Timeout, disconnect или неоднозначный 5xx не показывают, была ли генерация выполнена и списана ли оплата; соединение может прерваться при записи результата после расчёта, поэтому возможны повторные списания. Не повторяйте автоматически POST генерации или редактирования. Сначала проверьте записи потребления или логи запросов; сохраните возвращённый request ID и, если получены, заголовки X-BetterToken-Image-Receipt и X-BetterToken-Billing-State. Собственный request ID клиента не обеспечивает идемпотентность сервера; повторная отправка может создать новый запрос и списание. Отдельного endpoint проверки статуса нет.
Перед повторной отправкой исправьте отклонённые данные, аутентификацию или проблему квоты. Повторяйте 429 с backoff только после подтверждения отказа запроса. Не считайте все 5xx или транспортные ошибки безопасными для повтора.
Для предварительной авторизации BetterToken может удержать максимум: наибольшая применимая цена за единицу, умноженная на n. Поэтому баланса, достаточного для фактически доставленного изображения 1K, может не хватить на предварительную авторизацию; такой отказ возвращается как 403 с error.code=insufficient_user_quota. После обработки сумма рассчитывается по фактически доставленным изображениям. Корневой bettertoken_image_billing содержит итоговый settled_amount, валюту и amount, billing_resolution и размеры каждого результата. Денежные значения — decimal strings; фактическое число изображений может быть меньше n.
Обработка ошибок
Ошибка обычно возвращается как JSON. При отображении сообщения сначала прочитайте error.message, затем message, а после этого HTTP status text.
| HTTP status | Значение | Что делать |
|---|---|---|
400 | Некорректный JSON, отсутствует параметр или неподдерживаемый размер | Проверьте тело запроса. Не повторяйте автоматически. |
401 | API Key отсутствует или недействителен | Проверьте header Authorization: Bearer YOUR_API_KEY. |
402 или 403 | Недостаточно квоты или баланса, включая удержание средств | Проверьте error.code и квоту/баланс аккаунта. 403 с error.code=insufficient_user_quota означает, что баланс может быть ниже предварительной авторизации по верхнему пределу. |
429 | Rate limit, ограничение concurrency или занятый upstream | Повторяйте с backoff только после подтверждения отказа запроса. |
5xx | Ошибка gateway или upstream | Выполнение и списание могут быть неизвестны. Перед осознанной повторной отправкой проверьте логи и потребление. |
Чек-лист подключения
- Base URL:
https://bettertoken.ai/v1. - Заголовок содержит
Authorization: Bearer sk-.... - Для запроса используется
application/json. - Выберите доступный для запроса Model ID:
gpt-image-2,gpt-image-2.5-flareилиgpt-image-2.5-sunburst. - Используйте
response_format=b64_json.output_format— запрошенное значение; при сохранении определяйте формат по байтам. nпринимает целые числа от1до10. Рекомендуется1; изображений может быть меньше.sizeможно пропустить, задатьautoили указать допустимые размеры. Таблица выше не является закрытым списком.- HTTP-клиент допускает ожидание генерации в течение нескольких минут.
- Логи и скриншоты ошибок не раскрывают API Key или полное содержимое изображения в base64.
Смежные документы
/v1/images/generationsАвторизации
Используйте API Key BetterToken как bearer token. Не публикуйте API keys во frontend-коде, скриншотах, логах, тикетах или Git-репозиториях.
Тело application/json
Model ID GPT Image. Один BetterToken API Key работает со всеми доступными моделями.
"gpt-image-2"Prompt для генерации изображения.
"Футуристичный постер AI-продукта на светлом фоне, стеклянная фактура, чистая композиция, премиальный технологичный стиль"Допустимо 1–10; начните с 1. Может быть передано меньше изображений, чем запрошено. Перебирайте data[] и используйте расчет по фактическому результату.
1Опустите поле или передайте auto для автоматического размера. Для WxH обе стороны должны быть положительными и кратными 16, не более 3840 каждая; соотношение сторон не более 3:1, площадь 655360–8294400 пикселей. Примеры не являются закрытым списком: 2080x2080 тоже соответствует правилам. Проверяйте фактические размеры. Допустимые параметры не гарантируют доступный сервис.
"1024x1024"["auto","1024x1024","2048x2048","2080x2080","3840x2160"]Рекомендуется фиксировать b64_json, чтобы стабильно сохранять изображение.
"b64_json"Запрошенный формат; рекомендуется png, но перекодирование ответа в PNG не гарантируется. Определяйте PNG, JPEG или WebP по реальным байтам перед выбором расширения. Если нужен конкретный формат, преобразуйте файл самостоятельно.
"png"gpt-image-2 принимает auto, low, medium, high. Обе модели 2.5 также принимают xhigh и max. Если поле опущено, используется значение модели по умолчанию; JSON null считается отсутствующим, а multipart требует непустую строку. Допустимое значение не гарантирует доступный сервис для любого сочетания модели, размера и редактирования или улучшение изображения при повышении уровня.
"auto"Ответ
200Расширение тарификации BetterToken. Сумма определяется фактическими пикселями и тарифным уровнем результата, который может отличаться от запрошенного. Денежные суммы — десятичные строки; используйте значения из ответа.
OpenAI-совместимый ответ с изображениями. Перебирайте data[] и читайте b64_json каждого изображения, допуская дополнительные поля, например revised_prompt. Фактическое число изображений может быть меньше запрошенного.
1710000000Show child attributes
Содержимое изображения в кодировке Base64.
"iVBORw0KGgoAAAANSUhEUgAA...(truncated)"Необязательный переписанный prompt.
Расширение тарификации BetterToken. Сумма определяется фактическими пикселями и тарифным уровнем результата, который может отличаться от запрошенного. Денежные суммы — десятичные строки; используйте значения из ответа.
Show child attributes
Номера переданных изображений, фактические размеры, тарифные уровни и стоимость каждого изображения. index начинается с 0 и соответствует изображению в data[].
Уровень разрешения, определённый по запросу; он может отличаться от фактического тарифа.
{
"created": 1710000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
"revised_prompt": "<string>"
}
],
"bettertoken_image_billing": {
"currency": "<string>",
"settled_amount": "<string>",
"outputs": [
{
"index": 0,
"width": 1,
"height": 1,
"billing_resolution": "1K",
"currency": "<string>",
"amount": "<string>"
}
],
"partial": false,
"requested_resolution": "<string>"
}
}400Неверный формат запроса, отсутствующие параметры, ошибка разбора JSON или multipart, либо неверный формат размера.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}401API Key отсутствует или недействителен.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}402Недостаточно квоты или баланса.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}403Недостаточно баланса или квоты ключа: error.code равен insufficient_user_quota. Средств также должно хватать на резерв по максимальной цене уровня, умноженной на верхний предел числа изображений; затем выполняется расчет по результату. Проверяйте error.code, а не считайте любой 403 ошибкой доступа.
{
"error": {
"code": "insufficient_user_quota",
"message": "Insufficient balance or token quota."
}
}429Сработал rate limit, лимит параллельных запросов или upstream временно перегружен.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}500Ошибка gateway или upstream-сервиса.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}
