Generations API
Создание генераций, опрос статуса, список задач и загрузка референсов для image-to-image
Generations API — основной эндпоинт IskraGen. Одна и та же схема запроса работает для всех моделей: картинки, видео, озвучка, музыка. Тип медиа и набор параметров определяются выбранной моделью.
Все запросы авторизуются API-ключом (см. Authentication):
Authorization: Bearer iskr_live_<secret>
Базовый URL:
https://api.iskragen.ru/v1. Канонический публичный путь —/v1/*. Внутри приложения те же роуты смонтированы под/api/v1/*— это внутренняя деталь, в интеграциях используйте/v1/*.
Модель асинхронная
Генерация — асинхронная операция. POST /v1/generations не ждёт готового медиа: он ставит задачу в очередь, сразу списывает стоимость (hold) и возвращает HTTP 202 с id и статусом PENDING. Готовый результат вы получаете одним из двух способов:
- Polling — опрашивайте
GET /v1/generations/:id, покаstatusостаётсяPENDINGилиPROCESSING; все возможные значения перечислены ниже. - Webhooks — для длинных задач (видео, музыка) подпишитесь на
generation.completed/generation.failedи не опрашивайте вручную.
Основной жизненный цикл статуса:
PENDING → PROCESSING → SUCCEEDED
↘ FAILED (средства возвращаются на баланс автоматически)
| Статус | Значение |
|---|---|
PENDING | Задача принята и стоит в очереди. |
PROCESSING | Провайдер выполняет генерацию. |
SUCCEEDED | Готово. Результат в outputUrls. |
FAILED | Окончательная ошибка (после всех retry). Списанные средства возвращены. |
ENQUEUE_FAILED | Не удалось зарезервировать средства или передать задачу на обработку; обработка не началась. |
REFUNDED | — |
CANCELLED | — |
POST /v1/generations
Создать генерацию.
Тело запроса
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
modelSlug | string | да | Публичный slug модели IskraGen (например gpt-image-2-text-to-image). Источник правды — каталог (раздел «Discovery» ниже) и «ID модели» в карточке модели. |
prompt | string | обычно | Для Gemini 3.8 TTS с speakers и dialogue_turns не требуется: сервер собирает текст из реплик. Для остальных моделей обязателен. От 1 символа. Верхняя граница зависит от модели: по умолчанию 4000 символов, у отдельных моделей меньше или больше. Актуальное значение — поле promptMaxChars модели в GET /v1/catalog; абсолютный максимум запроса — 10 000 символов. Превышение лимита модели возвращает VALIDATION_ERROR (400) с details.reason: "PROMPT_TOO_LONG", details.limit и details.actual; деньги не списываются. |
negativePrompt | string | нет | До 2000 символов. |
params | object | нет | Параметры, специфичные для модели (например aspect_ratio, resolution, duration, input_urls). Мёрджатся поверх defaultParams модели. См. раздел «aspect_ratio vs width/height» ниже. |
width | integer | нет | 256–4096. Только для части прежних пиксельных моделей. Для актуального каталога используйте params.aspect_ratio + params.resolution. |
height | integer | нет | 256–4096. См. width. |
durationSec | integer | нет | 1–600. Длительность для видео/аудио, если модель принимает секунды. |
seed | integer | нет | ≥ 0. Для воспроизводимости. |
idempotencyKey | string | нет | 1–64 символа. Повторный запрос с тем же ключом и тем же телом вернёт ту же генерацию, а не создаст новую. Предпочтительный способ — заголовок Idempotency-Key (см. ниже). |
Заголовки
| Заголовок | Обяз. | Описание |
|---|---|---|
Idempotency-Key | нет | 1–64 символа. Повторный запрос с тем же ключом и тем же телом вернёт ту же генерацию. Если заголовок не передан, используется поле idempotencyKey из тела запроса; если переданы оба и значения различаются — приоритет у заголовка. Значение длиннее 64 символов или пустое → 400. |
Повтор с тем же idempotencyKey (в теле или в заголовке Idempotency-Key) в пределах одного пользователя возвращает существующую генерацию (id, status, costRub), если тело совпадает с исходным, не создаёт новую и не списывает деньги второй раз — даже если тело уже не проходит проверку параметров модели. Изменение модели, prompt, negativePrompt, параметров, размеров, длительности, seed, pricingVersion, expectedCostRub или quoteId возвращает 409 IDEMPOTENCY_KEY_REUSED без списания денег; для нового запроса нужен новый ключ. Порядок ключей в объектах params не влияет на сравнение; порядок элементов массивов сохраняется. maxCostRub в сравнении не участвует. Если одновременные запросы с одним ключом отличаются только maxCostRub, до фиксации первого запрос с меньшим бюджетом может получить 409 MAX_COST_EXCEEDED; после фиксации он получает ту же задачу. Генерации, созданные до появления сверки, возвращаются без сравнения тела.
Поиск по ключу идёт после проверок запроса, поэтому повтор получит отказ, а не генерацию, если:
- нет действующей авторизации —
401; - превышен общий лимит запросов —
429; - тело нарушает схему запроса, например
durationSec: 601—400; - аккаунт приостановлен или требуется привязка Telegram —
403; - модель больше не доступна —
403или404; - режим Suno временно недоступен —
503.
Такой отказ не затрагивает существующую генерацию и ничего не списывает. Пока первый запрос с этим ключом ещё выполняется, повтор с телом, не прошедшим проверку параметров модели, тоже получит 400.
curl -X POST https://api.iskragen.ru/v1/generations \
-H "Authorization: Bearer $ISKRAGEN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-42-retry-1" \
-d '{ "modelSlug": "gpt-image-2-text-to-image", "prompt": "Кот-космонавт" }'
Диалоги Gemini 3.8 TTS
Обе модели, google-gemini-3-8-flash-tts и google-gemini-3-8-flash-lite-tts, принимают диалог в params:
{
"modelSlug": "google-gemini-3-8-flash-tts",
"params": {
"speakers": [
{ "speaker_id": "Speaker 1", "voice_name": "Zephyr" },
{ "speaker_id": "Speaker 2", "voice_name": "Kore" }
],
"dialogue_turns": [
{ "speaker_id": "Speaker 1", "style": "Спокойно", "text": "Здравствуйте!" },
{ "speaker_id": "Speaker 2", "style": "Радостно", "text": "Привет! <laugh>" }
],
"filler_words": false,
"temperature": 1.01
}
}
В speakers — один или два участника с уникальными ID Speaker 1 / Speaker 2. В dialogue_turns — хотя бы одна непустая реплика; её speaker_id должен быть в списке участников. Порядок реплик сохраняется, style — свободное описание без отдельного ограничения длины. Доступные 70 голосов перечислены в схеме каталога; голос по умолчанию — Zephyr.
filler_words по умолчанию false, temperature — число от 0 до 2, по умолчанию 1. Лимит Искры — 4000 символов суммарного текста реплик. Считается длина строк UTF-16 без разделителей; стиль и имена участников в стоимость не входят. Каждая начатая тысяча символов стоит 4 ₽ для Flash и 2 ₽ для Flash Lite. Переданный prompt не меняет расчёт: сервер использует текст диалога. Старые сохранённые одиночные озвучки восстанавливаются как одна реплика.
Ответ 202 Accepted
{
"id": "0192f0c4-8a1e-7b3d-9f21-2c5e6a4b7d90",
"status": "PENDING",
"costRub": 7
}
costRub— стоимость, уже зарезервированная (hold) с баланса в момент запроса. ПриFAILEDвозвращается автоматически.id— UUIDv7, передавайте его вGET /v1/generations/:id.
Пример
curl -X POST https://api.iskragen.ru/v1/generations \
-H "Authorization: Bearer $ISKRAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modelSlug": "gpt-image-2-text-to-image",
"prompt": "Кот-космонавт на фоне Сатурна, фотореализм",
"params": { "aspect_ratio": "1:1", "resolution": "1K" }
}'
GET /v1/generations/:id
Получить генерацию по id. Используется для polling'а.
Ответ 200 OK
{
"id": "0192f0c4-8a1e-7b3d-9f21-2c5e6a4b7d90",
"userId": "0192...",
"modelId": "legacy-model-id",
"modelSlug": "gpt-image-2-text-to-image",
"modelName": "GPT Image 2",
"mediaType": "IMAGE",
"prompt": "Кот-космонавт на фоне Сатурна, фотореализм",
"params": { "aspect_ratio": "1:1", "resolution": "1K" },
"status": "SUCCEEDED",
"outputUrls": ["https://s3.twcstorage.ru/.../result.webp"],
"costRub": 7,
"mediaPriceRub": 6,
"chargeStatus": null,
"errorMessage": null,
"errorCode": null,
"startedAt": "2026-07-01T12:00:40.000Z",
"finishedAt": "2026-07-01T12:00:42.000Z",
"createdAt": "2026-07-01T12:00:39.000Z"
}
| Поле | Тип | Описание |
|---|---|---|
modelSlug | string | Публичный идентификатор модели. |
modelId | string | Устарело. Внутренний идентификатор; используйте modelSlug. |
status | string | PENDING | PROCESSING | SUCCEEDED | FAILED | REFUNDED | CANCELLED | ENQUEUE_FAILED. |
outputUrls | string[] | Ссылки на результат (S3). Пусто, пока status ≠ SUCCEEDED. |
errorCode / errorMessage | string | null | Заполняются при FAILED. |
mediaPriceRub | number | null | Реальная цена медиа (когда доступна). |
chargeStatus | string | null | Технический статус биллингового контура. null — контур для вашего аккаунта не задействован (текущий режим по умолчанию): списание и возврат уже произошли, но отдельного статуса для них нет — ориентируйтесь на status и баланс. Если контур включён, возможные значения — PENDING / CHARGED / RELEASED / FAILED / FAILED_EXPIRED. |
startedAt / finishedAt | string | null | ISO-8601 UTC. |
Пример polling'а (Node.js)
async function waitForResult(id) {
for (;;) {
const res = await fetch(`https://api.iskragen.ru/v1/generations/${id}`, {
headers: { Authorization: `Bearer ${process.env.ISKRAGEN_API_KEY}` },
});
const gen = await res.json();
if (gen.status === "SUCCEEDED") return gen.outputUrls;
if (gen.status !== "PENDING" && gen.status !== "PROCESSING") {
throw new Error(`${gen.status}: ${gen.errorCode}: ${gen.errorMessage}`);
}
await new Promise((r) => setTimeout(r, 2000)); // 2 сек между опросами
}
}
GET /v1/generations/:id/download
Скачать файл результата по индексу. Авторизация — API-ключ или сессия.
Query-параметры
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
index | integer | 0 | Номер файла результата, от 0 до 15. |
API сам отдаёт байты файла, а не редирект или ссылку. Ответ содержит Content-Type, Content-Disposition: attachment; filename="…", Cache-Control: private, no-store и, если размер известен, Content-Length.
curl -L -o result.png \
-H "Authorization: Bearer $KEY" \
https://api.iskragen.ru/v1/generations/<id>/download
Ошибки:
| HTTP | code | Когда |
|---|---|---|
| 404 | NOT_FOUND | Генерации нет, она принадлежит другому пользователю или у неё нет файла с таким index. |
| 502 | OUTPUT_FETCH_FAILED | Файл не удалось получить из хранилища. |
GET /v1/generations
Список генераций пользователя, cursor-пагинация (новые первыми).
Query-параметры
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
limit | integer | 20 | 1–100. |
cursor | string | — | createdAt последнего элемента предыдущей страницы (ISO 8601); используйте значение nextCursor. |
status | string | — | Фильтр: PENDING | PROCESSING | SUCCEEDED | FAILED. |
modelId | string | — | Один или несколько modelSlug через запятую. Прежние идентификаторы моделей по-прежнему принимаются. |
Ответ 200 OK
{
"items": [
{
"id": "0192...",
"modelSlug": "gpt-image-2-text-to-image",
"modelId": "legacy-model-id",
"status": "SUCCEEDED",
"outputUrls": ["..."],
"createdAt": "..."
}
],
"nextCursor": "2026-07-01T12:00:39.000Z"
}
Когда nextCursor равен null — страниц больше нет.
modelId в элементах ответа устарел и сохранён для совместимости; используйте modelSlug.
GET /v1/generations/models
Возвращает модели, которые встречаются в истории пользователя, и число генераций по каждой из них.
{
"models": [
{
"id": "legacy-model-id",
"slug": "gpt-image-2-text-to-image",
"name": "GPT Image 2",
"count": 3
}
]
}
Поле id устарело и сохранено для совместимости; используйте slug.
Discovery: slug и параметры
Список моделей, их публичные slug'и, дефолтные параметры и JSON-схему параметров отдаёт публичный каталог (без авторизации):
curl https://api.iskragen.ru/v1/catalog
{
"total": 22,
"models": [
{
"slug": "gpt-image-2-text-to-image",
"displayName": "GPT Image 2",
"mediaType": "IMAGE",
"sellPriceRub": 6,
"supportsImg2Img": true,
"defaultParams": { "aspect_ratio": "auto", "resolution": "1K" },
"paramsSchema": { "...": "..." }
}
]
}
slug→ это значение и естьmodelSlugдляPOST /v1/generations.defaultParams— что подставится, если вы не передали поле вparams.paramsSchema— допустимые ключи и значенияparamsдля конкретной модели.
Те же данные человекочитаемо есть в каталоге /models и в карточке каждой модели.
aspect_ratio vs width/height
Это частый источник путаницы. Правило простое:
- Актуальный каталог задаёт размер через
params:params.aspect_ratio— соотношение сторон ("1:1","16:9","9:16","4:3","3:4","21:9","5:4","3:2","4:5","2:3","auto").params.resolution— качество ("1K","2K","4K"). Влияет на цену.- Верхнеуровневые
width/heightэтими моделями игнорируются.
- Часть прежних пиксельных моделей использует верхнеуровневые
width/heightв пикселях.
Что поддерживает конкретная модель — смотрите в paramsSchema из каталога или в карточке модели. params всегда переопределяют defaultParams; опущенные поля берутся из дефолтов модели.
aspect_ratio: "auto"→ только1K. В режимеautoдоступно единственное разрешение1K; комбинацияauto+2K/4Kне поддерживается. Задайте явное соотношение сторон, если нужно 2K/4K.
Image-to-image: передача референса
Референс не передаётся в теле POST /v1/generations напрямую. Файл загружается одним запросом POST /v1/files, а url из ответа подставляется в params генерации.
Шаг 1 — загрузить файл: POST /v1/files
curl -X POST https://api.iskragen.ru/v1/files \
-H "Authorization: Bearer iskr_live_..." \
-F "file=@reference.png"
Тело — multipart/form-data с ровно одним файловым полем file; нефайловые поля игнорируются. Авторизация — API-ключ или сессия.
Ответ 201:
{
"id": "01991d2e-7b1a-7c3e-9f00-3d2a1b4c5d6e",
"url": "https://s3.twcstorage.ru/iskragen-inputs/prod/<userId>/inputs/<uuid>.png",
"contentType": "image/png",
"sizeBytes": 123456,
"originalFilename": "reference.png",
"createdAt": "2026-09-07T12:00:00.000Z"
}
url подставляется в params генерации как есть.
Типы: image/png, image/jpeg, image/webp, image/bmp, image/tiff, image/gif, video/mp4, video/quicktime, audio/mpeg (mp3), audio/wav. Содержимое сверяется с заявленным типом по сигнатуре.
Лимиты: изображения — 30 МБ, аудио — 50 МБ, видео — 100 МБ (десятичные МБ). Не больше 60 запросов в минуту и не больше 3 одновременных загрузок на пользователя.
Ошибки (стандартный конверт { "error": { "code", "message", "requestId", "timestamp" } }):
| Код | code | Когда |
|---|---|---|
| 400 | VALIDATION_ERROR | тело не multipart; поля file нет или их два; тип не поддерживается; содержимое не совпадает с заявленным типом; пустой файл; «Файл больше N МБ» |
| 401 | AUTHENTICATION_ERROR | нет API-ключа или сессии |
| 429 | RATE_LIMIT_ERROR | превышены 60 запросов в минуту или 3 одновременные загрузки |
| 502 | STORAGE_UPLOAD_FAILED | хранилище недоступно, повторите запрос |
Шаг 2 — создать генерацию, передав url в params
Имя поля зависит от модели (смотрите paramsSchema в каталоге / карточку модели). Для image-to-image моделей это обычно input_urls (массив ссылок):
curl -X POST https://api.iskragen.ru/v1/generations \
-H "Authorization: Bearer $ISKRAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modelSlug": "gpt-image-2-image-to-image",
"prompt": "Тот же кот, но в стиле акварели",
"params": {
"input_urls": ["https://s3.twcstorage.ru/iskragen-inputs/prod/<userId>/inputs/<uuid>.png"],
"aspect_ratio": "1:1",
"resolution": "1K"
}
}'
Дальше — обычный polling GET /v1/generations/:id.
Альтернатива: прямая загрузка через presigned URL
Нужна, если файл заливается напрямую из браузера или клиента в хранилище, минуя API.
Получить presigned URL
curl -X POST https://api.iskragen.ru/v1/uploads/presign-input \
-H "Authorization: Bearer $ISKRAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "contentType": "image/png", "size": 812345 }'
Ответ 200:
{
"url": "https://s3.twcstorage.ru/...&X-Amz-Signature=...",
"key": "users/<userId>/inputs/<uuid>.png",
"finalUrl": "https://s3.twcstorage.ru/.../inputs/<uuid>.png",
"expiresIn": 900
}
contentType— MIME файла (image/jpeg,image/png,image/webp,image/bmp,image/tiff,image/gif).size— размер в байтах (лимит 30 МБ).urlживётexpiresInсекунд (15 минут).
Загрузить файл (PUT)
curl -X PUT "$PRESIGNED_URL" \
-H "Content-Type: image/png" \
--data-binary @reference.png
Заголовок Content-Type и размер тела должны совпадать с contentType и size из presign-запроса, иначе хранилище ответит 403.
После PUT в params генерации уходит finalUrl из ответа presign — шаг 2 дальше без изменений.
Исключение — референс-видео моделей Seedance (ниже): файл из presigned-загрузки для них не подходит.
Референс-видео у Seedance 2, Seedance 2 Fast и Seedance 2.5
params.reference_video_urls — массив ссылок на видео, загруженные через POST /v1/files. Длительность каждого ролика сервер измеряет при загрузке; сторонние ссылки и файлы из POST /v1/uploads/presign-input не принимаются. Суммарная длительность входа — не больше 15 секунд у Seedance 2 и Seedance 2 Fast и не больше 30 секунд у Seedance 2.5. Одна и та же ссылка, переданная дважды, считается дважды.
Провайдер тарифицирует и выход, и вход, поэтому цена с референс-видео считается так:
цена = цена_без_референса × (вход + выход) / выход × коэффициент_модели
вход— суммарная длительность референс-видео в секундах, округлённая вверх до целой секунды;выход— длительность клипа (params.duration);- коэффициент: Seedance 2 —
0.610, Seedance 2 Fast —0.605, Seedance 2.5 —0.603.
Пример: клип 5 секунд и референс 15 секунд — цена_без_референса × 20 / 5 × 0.61, то есть в 2,44 раза дороже того же клипа без референса. Сумма округляется до копеек и возвращается в costRub ответа.
Ошибки
Ошибки возвращаются в едином формате (подробнее — Errors):
{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance",
"requestId": "req_...",
"timestamp": "2026-07-01T12:00:00.000Z"
}
}
Коды, специфичные для Generations API:
| HTTP | code | Когда |
|---|---|---|
| 400 | VALIDATION_ERROR | Некорректное тело: пустой prompt, width/height вне диапазона и т.п. |
| 400 | REFERENCE_VIDEO_NOT_UPLOADED | Ссылка в reference_video_urls не ведёт на ваш файл из POST /v1/files (сторонний URL, чужой файл, файл из presign-input). |
| 400 | REFERENCE_VIDEO_NOT_A_VIDEO | В reference_video_urls передан ваш файл, но не видео. |
| 400 | REFERENCE_VIDEO_DURATION_UNKNOWN | Длительность ролика не удалось определить при загрузке — перезагрузите файл. |
| 400 | REFERENCE_VIDEO_TOO_LONG | Суммарная длительность референс-видео больше лимита модели. |
| 400 | REFERENCE_VIDEO_TOO_MANY | В reference_video_urls больше 10 ссылок. |
| 401 | AUTHENTICATION_ERROR | Нет/неверный API-ключ. |
| 402 | INSUFFICIENT_BALANCE | Не хватает средств. В details — required и available. |
| 403 | MODEL_NOT_AVAILABLE | Модель существует, но недоступна для новых генераций (не в публичном каталоге). |
| 404 | NOT_FOUND | Модель по modelSlug не найдена, либо id генерации чужой/несуществующий. |
| 409 | IDEMPOTENCY_KEY_REUSED | Ключ уже использован для запроса с другим телом; повторите с новым ключом. |
| 429 | RATE_LIMIT_ERROR | Превышен лимит 5 одновременных генераций (PENDING+PROCESSING). Дождитесь завершения текущих. |
Что дальше
- Webhooks — уведомления вместо polling'а для длинных задач.
- Errors — полный формат ошибок и коды.
- Rate limits — лимиты запросов и конкурентности.
- Interactive API Reference — все эндпоинты с тестированием в браузере.