Генерация картинок
/v1/images/generationsКартинки приходят в base64 тем же ответом; долгая генерация возвращает джоб с id (202).
Запрос
modelstringbodyобязательноpromptstringbodyобязательноEMPTY_PROMPT)nintegerbody= 1aspect_ratiostringbody= 1:1resolutionstringbody= 1Knano-banana-pro есть)orientationstringbody= squareaspect_ratioimagestring|arraybodyresponse_formatstringbodyОтветы
200
{
"created": 0,
"cost_usd": "0.027",
"data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" } ]
}Подробности
Нужен ключ в заголовке Authorization: Bearer или x-api-key.
Шлюз создаёт джобу, резервирует под неё деньги (под per-user локом, поэтому два одновременных запроса не пройдут по одному остатку), отправляет её провайдеру и сам опрашивает его до 150 с. Успел — приходит 200 с картинками в b64_json; не успел — 202 с { id, status, estimated_cost_usd }, и результат забирается через GET /v1/images/jobs/{job_id}. Резерв при этом остаётся на месте, так что деньги не «освобождаются» на время генерации.
Ссылок на CDN провайдера в ответе не бывает никогда: если провайдер вернул URL, шлюз скачивает картинку сам и отдаёт base64. Поэтому response_format принимается и игнорируется — результат всегда b64_json. Неизвестные поля тела тоже молча отбрасываются: наружу уезжает только то, что есть в аллоулисте модели.
Про поля. Неизвестная или выключенная админом модель, отсутствующий prompt, нецелое или выходящее за 1–10 n и значение параметра вне набора своей модели — всё это 400 у нас, до провайдера. Набор aspect_ratio зависит от модели: у части он шире (плюс 3:2, 2:3, 21:9), а часть моделей вместо aspect_ratio принимает orientation; поле, которого у модели нет, молча отбрасывается. На цену не влияет ни resolution, ни то, чем задан кадр: тариф — за картинку. n провайдеру не уезжает вовсе — он задаёт размер резерва, а списывается по числу вернувшихся картинок (не вернулось ни одной — по n). Отказ провайдера на сабмите по 5xx или сети оставляет деньги в резерве и приносит id в теле ошибки: джобу добивает реконсайлер, он же освободит резерв, если провайдер её так и не взял. А вот 4xx провайдера — окончательный отказ: джоба проваливается сразу, и резерв освобождается, не дожидаясь реконсайлера.
Деньги: у завершённой генерации в ответе cost_usd — ровно то, что списано, у идущей estimated_cost_usd — размер резерва. Провалившаяся генерация не тарифицируется и приходит с "cost_usd": "0". Счёт за медиа ведём мы сами, отдельно от текста. Ошибки приходят одной формой; code в ней есть там, где его дал провайдер, а у отказа на сабмите добавляется id джобы: { "error": { "message": "...", "type": "...", "code": "PROVIDER_CODE" } }.
Референс-картинки (image-to-image, тот же персонаж или стиль) передаются в теле как image — одна строка или массив; принимаются также images, image_url, image_urls, input_image, init_image, ref_images. Значением может быть публичный URL, data-URL или голый base64, и мешать формы в одном запросе можно: URL шлюз сам не скачивает и передаёт провайдеру ссылкой, а base64 декодирует и передаёт байтами. Байты шлюз узнаёт по сигнатуре (PNG, JPEG, GIF, WebP) и режет на 80 МБ на каждый вход — больше даёт 400 ещё до провайдера. Вход, который прошёл наш предел, может отклонить уже модель по своим правилам: тогда её код приходит в error.code — FILE_TOO_LARGE по размеру, FILE_TYPE_NOT_ALLOWED по типу. Количество референсов шлюз не ограничивает; сколько из них учтёт модель — на её стороне. Значение, которое не разобралось ни как URL, ни как base64, молча отбрасывается: запрос уйдёт без этого референса и без ошибки.
Срок жизни результата — 7 дней. Дальше байты уезжают из базы в архив, result_url очищается, и тот же GET /v1/images/jobs/{job_id} отвечает { "status": "completed", "archived": true, "data": [] }. Это «срок вышел», а не «генерация ничего не дала» — сохраняй картинки у себя сразу, как получил. Строка джобы и её деньги не удаляются никогда: ретеншен уносит только payload.