Руководства
Генерация изображений
Асинхронно отправляйте задачи генерации и редактирования изображений, опрашивайте статус и скачивайте изображения по подписанным ссылкам.
Image API Felo генерирует и редактирует изображения с помощью моделей из каталога Felo. API асинхронный: запрос на отправку сразу возвращает ID задачи, после чего вы опрашиваете задачу до терминального состояния.
На этой странице описан контракт, специфичный для изображений. Общий жизненный цикл задач см. в разделе Асинхронные задачи.
Перед началом
- API key. См. Аутентификация.
- Модель с
model_kind, равнымimage_generation. См. раздел «Найти модель изображений» ниже. - Base URL:
https://openapi.felo.ai.
Отличия от OpenAI Images API
Путь похож на OpenAI Images API, но ответ — нет:
| OpenAI Images API | Image API Felo | |
|---|---|---|
| Ответ на отправку | 200 с данными изображения | 202 с task_id, status: "queued" |
| Когда изображение готово | В ответе на отправку | После того как polling дойдёт до succeeded |
| Данные изображения | b64_json или url | Подписанный url с ограниченным сроком действия |
| Ошибки запроса | HTTP-ошибка при отправке | Обычно status: "failed" у задачи |
Не отправляйте openai.images.generate() на этот endpoint. SDK ожидает синхронный массив data и не умеет опрашивать задачу. Вызывайте endpoint напрямую по HTTP и опрашивайте задачу либо оберните оба шага в свой клиент.
Отправить задачу
curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-image",
"prompt": "A studio product photo of a ceramic coffee cup on warm linen, soft morning light",
"resolution": "2K",
"aspect_ratio": "4:3"
}'Успешная отправка возвращает HTTP 202:
{
"task_id": "6d1f0c9a-...",
"status": "queued",
"kind": "image",
"outputs": []
}202 означает только то, что платформа приняла задачу. Это не значит, что prompt, параметры или референсные изображения корректны. Запрос к upstream выполняется после ответа, поэтому большинство проблем с запросом проявляется позже как неудачная задача. Исключение — маршрутизация модели: chat- или video-модель отклоняется при отправке.
Опрашивать до терминального состояния
curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
-H "Authorization: Bearer ${FELO_API_KEY}"| Статус | Значение | Что делать |
|---|---|---|
queued | Принята, ожидает запуска | Продолжать polling |
running | Модель генерирует | Продолжать polling |
succeeded | Терминальный; outputs заполнен | Скачать результаты |
failed | Терминальный; прочитайте error.message | Исправить запрос; не повторять без изменений |
interrupted | Терминальный; результат не удалось восстановить | Отправить задачу заново |
При ошибке задачи HTTP-статус остаётся 200. Проверяйте status в теле ответа, а не только HTTP-статус.
Начните с интервала 2–5 секунд и постепенно увеличивайте его. Большинство изображений готово в течение минуты; вывод 4K и редактирование с большим числом референсов занимают дольше. Всегда задавайте собственный дедлайн.
import os
import time
import requests
BASE = "https://openapi.felo.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['FELO_API_KEY']}"}
def generate_image(prompt: str, **params) -> list[dict]:
response = requests.post(
f"{BASE}/api/v1/images/generations",
headers=HEADERS,
json={"model": "gemini-3-pro-image", "prompt": prompt, **params},
timeout=30,
)
response.raise_for_status()
task = response.json()
deadline = time.monotonic() + 300
delay = 2.0
while time.monotonic() < deadline:
time.sleep(delay)
delay = min(delay * 1.5, 10.0)
poll = requests.get(
f"{BASE}/api/v1/images/generations/{task['task_id']}",
headers=HEADERS,
timeout=30,
)
poll.raise_for_status()
task = poll.json()
if task["status"] == "succeeded":
return task["outputs"]
if task["status"] in {"failed", "interrupted"}:
message = task.get("error", {}).get("message", task["status"])
raise RuntimeError(message)
raise TimeoutError(f"image task {task['task_id']} did not finish")Получить и сохранить результаты
После успешного завершения outputs содержит по одной записи на каждое сгенерированное изображение:
{
"task_id": "6d1f0c9a-...",
"status": "succeeded",
"kind": "image",
"outputs": [
{
"media_type": "image/png",
"url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
}
]
}outputsпуст, пока задача не завершится успешно.url— подписанный URL. Он скачивается без API key, поэтому обращайтесь с ним как с bearer-ссылкой.- URL имеет ограниченный срок действия. Параметр
exp— время истечения. Скачайте файл и сохраните его в свой bucket или файловую систему; задача не является постоянным хранилищем. - Повторный polling после истечения срока возвращает тот же просроченный URL. Новый URL не выдаётся.
- Ответ не содержит изображение в base64.
for index, output in enumerate(outputs):
image = requests.get(output["url"], timeout=60)
image.raise_for_status()
with open(f"image-{index}.png", "wb") as file:
file.write(image.content)Редактировать изображение
Передайте референсные изображения в input_references. Модель использует их как контекст; в prompt по-прежнему нужно описать изменение.
curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-image",
"prompt": "Keep the product and framing. Replace the background with a sunlit marble countertop.",
"resolution": "2K",
"aspect_ratio": "4:3",
"input_references": [
{
"type": "image_url",
"image_url": {"url": "https://example.com/product.png"}
}
]
}'Каждый референс — HTTP(S) URL или base64 data URL. Порядок референсов сохраняется; при необходимости ссылайтесь на изображения по позиции в prompt. Текущие модели принимают до 14 референсов.
Поля запроса
| Поле | Обязательно | Описание |
|---|---|---|
model | Да | ID модели из каталога, например gemini-3-pro-image. Не используйте upstream-ID вида google/... |
prompt | Да | Текстовая инструкция. При редактировании опишите изменение и то, что должно остаться прежним |
resolution | Нет | Уровень вывода. Текущие модели принимают 1K, 2K или 4K |
aspect_ratio | Нет | Соотношение сторон. Допустимые значения зависят от модели |
n | Нет | Количество изображений. Текущие модели принимают 1 |
input_references | Нет | Референсные изображения для редактирования или композиции |
Текущие модели изображений:
| ID модели | Разрешения | Соотношения сторон | Изображений на задачу | Референсы |
|---|---|---|---|---|
gemini-3-pro-image | 1K, 2K, 4K | 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9 | 1 | До 14 |
gemini-nano-banana-2.1 | 1K, 2K, 4K | 1:1, 1:4, 1:8, 2:3, 3:2, 3:4, 4:1, 4:3, 4:5, 5:4, 8:1, 9:16, 16:9, 21:9 | 1 | До 14 |
Чтобы закрепить поставщика, отправьте заголовок X-Felo-Channel со значением channel code из списка channels модели. См. Каналы и маршрутизация провайдеров.
Найти модель изображений
Отдельного endpoint со списком моделей изображений нет. Запросите общий каталог и отфильтруйте по model_kind:
curl "https://openapi.felo.ai/api/v1/models" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
| jq '.data[] | select(.model_kind == "image_generation") | {id, name}'GET /api/v1/models/{model_id} возвращает каналы модели и опубликованные тарифы.
supported_parameters в общем каталоге — список параметров уровня протокола. Для моделей изображений он не перечисляет надёжно поля изображений выше, поэтому не стройте по нему запрос. Используйте таблицу полей на этой странице, а ID модели проверяйте по каталогу.
Тарификация
Генерация изображений тарифицируется по опубликованным тарифам модели. В каталоге, помимо текстовых prompt и completion, есть input_image и output_image. Тарифы изображений — это тарифы за токены: resolution меняет число выходных image-токенов на одно изображение, поэтому 4K стоит дороже 1K. Референсные изображения добавляют входные image-токены.
В ответе задачи нет объекта usage. Фактическое списание смотрите в записях об использовании Console Billing.
Задача, завершившаяся со статусом failed или interrupted, не даёт результата и не тарифицируется. Ответ 402 при отправке означает, что задача не была создана.
Ошибки
Ошибки уровня endpoint на маршруте изображений используют конверт ошибок OpenAI:
{
"error": {
"message": "Model kind does not match this generation endpoint",
"type": "invalid_request_error",
"param": null,
"code": "model_kind_mismatch"
}
}Request ID находится в заголовке ответа X-Request-Id. Записывайте его вместе с task ID.
| HTTP | error.code | Значение |
|---|---|---|
| 400 | invalid_request_error | Нет model или тело не является JSON-объектом |
| 400 | model_not_configured | ID модели отсутствует в активном каталоге |
| 400 | chat_model_not_allowed | В endpoint изображений отправлена chat-модель |
| 400 | model_kind_mismatch | В endpoint изображений отправлена video- или другая не-image модель |
| 402 | insufficient_balance | Недостаточно кредитов; задача не создана |
| 404 | generation_task_not_found | ID задачи неизвестен или принадлежит другому аккаунту |
| 429 | daily_spend_limit_exceeded | Достигнут дневной лимит расходов аккаунта |
| 503 | generation_unavailable | Генерация временно недоступна; повторите позже |
Ошибки аутентификации описаны в разделе Ошибки, лимиты и повторные попытки.