API Pixyn: генерация из своего кода
Ключ даёт вашему коду тот же набор нейросетей, настроек и слотов, что человек видит в студии, и списывает токены с того же баланса. Отдельного тарифа за доступ нет. Выпускается в кабинете: Профиль → API . Показывается один раз.
С чего начать
- Выпустите ключ и положите его в переменную окружения.
- Заберите каталог, оттуда берутся ключи моделей, настроек и слотов.
- Спросите смету: сколько спишется именно за ваш запрос.
- Запустите генерацию и опрашивайте статус до результата.
export PIXYN_API_KEY=pxn_live_… Ключ идёт заголовком Authorization: Bearer … и работает от вашего имени: генерации создаются на ваш аккаунт, токены снимаются с вашего баланса. По умолчанию он умеет всё, что умеете вы сами. При выпуске набор можно урезать: например, ключ только на чтение каталога не потратит ни одного токена, даже если его украдут.
| Метод | Путь | Право | Зачем |
|---|---|---|---|
| GET | /api/v1/me | не нужен | Чей ключ, какие права, какие лимиты. |
| GET | /api/v1/models | models:read | Каталог: группы, поколения, настройки, слоты, цена. |
| POST | /api/v1/estimate | models:read | Сколько токенов спишется за такой запрос. |
| POST | /api/v1/generations | generations:create | Запустить генерацию. |
| GET | /api/v1/generations/:id | generations:read | Статус и результат одной генерации. |
| GET | /api/v1/generations | generations:read | Список своих генераций по API. |
Каталог нейросетей
Устроен как выбор в студии: группа (бренд) → поколение → тип входа → настройки. Ключи настроек и слотов берите только отсюда. Они разные у каждой модели и меняются вместе с ней.
curl -s "https://pixyn.ru/api/v1/models?category=video" \
-H "Authorization: Bearer $PIXYN_API_KEY"{
"groups": [{
"name": "Kling",
"category": "video",
"variants": [{
"id": "fal-ai-kling-video-v3-pro-image-to-video",
"input_kind": "image2video",
"price": { "base_tokens": 35, "included_seconds": 5, "per_extra_second_tokens": 7 },
"settings": [{ "key": "cfg_scale", "type": "number", "minimum": 0, "maximum": 1, "default": 0.5 }],
"slots": [{ "key": "start_image_url", "type": "frame-start", "required": true }],
"defaults": { "resolution": "1080p" },
"hidden_settings": ["seed"],
"media_tokens": null
}]
}]
}- defaults: предустановки модели. Не отправите, и результат разойдётся с тем, что даёт сайт.
- hidden_settings: поля, скрытые в интерфейсе. В запрос они всё равно уходят со значением по умолчанию, поэтому мы их показываем.
- slots не всегда про файл: enum-select означает выбор из списка (голос, аватар).
- media_tokens: как модель узнаёт файлы в тексте. У Seedance reference-to-video поле такое: { "image": "@Image{n}", "video": "@Video{n}", "audio": "@Audio{n}", "numbering": "per-kind" }. Второй файл из image_urls в промпте зовётся @Image2. null у отдельного вида означает, что ссылок этого вида в тексте нет: файлы идут в поля слотов (первый и последний кадр). Если media_tokens равен null целиком, токены из промпта вырезаются.
- numbering внутри media_tokens: чья шкала у номера {n}. При per-kind счёт идёт внутри каждого вида отдельно. При cross-kind шкала одна на видео и картинки, причём видео идут первыми: у варианта wan-v26-reference-to-video-flash при двух видео и одной картинке видео получают Character1 и Character2, а картинка Character3. Вывести это из шаблонов нельзя: у обоих видов написано одно и то же. Поэтому поле приходит отдельно и стоит у каждой модели с токенами.
- base_tokens это только стартовая часть цены. Для видео секунды сверх включённых считаются отдельно.
Сколько спишется
Смету считает тот же код, который потом списывает токены. Поэтому число из /estimate совпадает с фактическим списанием при тех же параметрах. Считать на своей стороне не нужно: у части моделей цена зависит от длительности, качества и длины текста одновременно.
curl -s -X POST https://pixyn.ru/api/v1/estimate \
-H "Authorization: Bearer $PIXYN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "fal-ai-kling-video-v3-pro-image-to-video",
"duration": 10,
"settings": { "resolution": "1080p" }
}' Так не стоит: взять base_tokens из каталога и показать пользователю как итог. Для видео это стартовая часть, и на десятисекундном ролике разница выйдет заметной. Запуск и результат
Настройки идут плоским объектом settings ключами из каталога, медиа объектом media ключами слотов. Разбираться, какому провайдеру в какой конверт класть параметры, не нужно: это делает сервер. Ответ приходит сразу со статусом pending, генерация идёт в фоне. Картинки обычно готовы за секунды, видео заметно дольше.
curl -s -X POST https://pixyn.ru/api/v1/generations \
-H "Authorization: Bearer $PIXYN_API_KEY" \
-H "Idempotency-Key: 8f14e45f-ea6a-4f2b-9c1d-0b6f2a1d77e0" \
-H "Content-Type: application/json" \
-d '{
"model": "fal-ai-kling-video-v3-pro-image-to-video",
"prompt": "кот едет на скейте по набережной, вечерний свет",
"duration": 10,
"settings": { "resolution": "1080p", "cfg_scale": 0.7 },
"media": { "start_image_url": "https://example.com/cat.jpg" }
}'
# в ответе придут id и статус pending; результат забирать так:
curl -s https://pixyn.ru/api/v1/generations/GEN_ID \
-H "Authorization: Bearer $PIXYN_API_KEY"Idempotency-Key защищает от двойного списания: с тем же ключом вернётся та же генерация и ответ 200 вместо 201. Ключ помнится сутки. Ставьте его на каждый запуск, ведь сетевой таймаут не означает, что запрос не дошёл.
Из чата: MCP
MCP это способ, которым Claude, ChatGPT и VS Code подключают внешние инструменты. Подключите наш сервер, и можно просить ассистента сгенерировать картинку или видео словами. Он сделает это через ваш аккаунт и ваш баланс, а готовое покажет прямо в переписке, забирать результат откуда-то ещё не нужно.
Claude Code, одной командой
claude mcp add --transport http pixyn https://pixyn.ru/api/mcp \
--header "Authorization: Bearer $PIXYN_API_KEY"Claude Desktop, Cursor и VS Code через конфиг
Нужны ровно два значения: адрес https://pixyn.ru/api/mcp и заголовок Authorization: Bearer <ваш ключ>. Форма файла у клиентов слегка разная, вот общий вид, впишите его туда, где ваш клиент держит список MCP-серверов.
{
"mcpServers": {
"pixyn": {
"type": "http",
"url": "https://pixyn.ru/api/mcp",
"headers": { "Authorization": "Bearer pxn_live_…" }
}
}
}Заголовок с ключом это не опция. Без него сервер добавится и будет виден в списке, но первый же вызов вернёт 401: своего входа по логину у MCP нет, ключ и есть вход.
Что сказать ассистенту
Дальше обычными словами, модель сама подберёт инструмент и подставит параметры из каталога. Просить «вызови create_generation» не нужно.
«Покажи, какие есть модели для видео из картинки»
«Сколько будет стоить 10 секунд в Kling v3 Pro в 1080p?»
«Оживи это фото: пусть камера медленно отъезжает. Начальный кадр вот по этой ссылке»
«Открой студию, я сам выберу модель»Ассистент поставит генерацию в очередь, дождётся её и покажет ссылку на готовое прямо в переписке. Если модель платная и дорогая, попросите сначала смету, это отдельный инструмент, и он ничего не списывает.
- Инструменты: каталог, смета, запуск, статус, история, баланс.
- Отдельная команда открывает окно выбора прямо в чате с теми же нейросетями, поколениями и настройками, что на сайте.
- Запуск и получение результата это два разных вызова. Видео делается минутами, ждать его внутри одного вызова хост не даст.
- Права те же, что у ключа: ключ без запуска покажет каталог и смету, но не потратит токены.
Доставка на свой сервер
Необязательная штука. Нужна, если чата нет вовсе и опрашивать статус в цикле неудобно: бот, бэкенд, крон. Подпишите адрес в кабинете, и мы придём POST-запросом, когда генерация закончится. События: generation.completed, generation.failed, а для раздела «Инстаграм» ещё instagram.lead (кодовое слово сработало, ссылка ушла в личку) и instagram.message (входящее сообщение от контакта). Полный справочник с описаниями отдаёт GET /api/user/webhooks/events.
X-Pixyn-Signature: sha256=<подпись>
X-Pixyn-Timestamp: 1786000000
{
"event": "generation.completed",
"data": {
"id": "gen_…",
"status": "completed",
"output": ["https://gen.pixyn.ru/m/…"],
"error": null,
"tokens_spent": 70
}
}Подпись проверять обязательно. Адрес рано или поздно попадает в логи или на скриншот, и без проверки любой сможет прислать вам «результат». Подписывается строка «отметка времени + точка + тело», ключом служит секрет подписки. Отметка входит в подпись специально: без неё перехваченный запрос повторяется бесконечно.
import crypto from 'node:crypto'
function verify(rawBody, headers, secret) {
const ts = Number(headers['x-pixyn-timestamp'])
// старше пяти минут — отвергаем: иначе перехваченный запрос можно повторять
if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > 300) return false
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(ts + '.' + rawBody)
.digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(headers['x-pixyn-signature'] ?? '')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}- Секрет показывается один раз при создании подписки, дальше только маска.
- Отвечайте быстро любым 2xx, работу делайте асинхронно: мы ждём не дольше десяти секунд.
- Не ответили? Повторим до пяти раз с растущими паузами. Десять неудач подряд, и подписка отключится; причина и код видны в кабинете, там же включается обратно.
- Приходят только генерации по ключу. Сделанное руками на сайте наружу не уходит.
- Подписками управляют только из кабинета, API-ключ этого не может. Иначе украденный ключ настроил бы себе канал утечки результатов.
Границы
- Отмены нет. Токены уходят в момент отправки запроса нейросети, остановить запущенное нельзя. Проверяйте параметры сметой заранее.
- Возврат только за наш сбой. Упало на нашей стороне, токены вернутся автоматически. «Не понравился результат» возвратом не считается.
- Файлы принимаются ссылкой. Загрузки тела файла нет: медиа передаётся абсолютной https-ссылкой, доступной нашему серверу.
- История видна только по API. Сделанное на сайте через ключ не видно.
- Одновременных генераций ограниченное число. Упёрлись в потолок? Ручка ответит 429 с кодом CONCURRENCY_LIMIT_EXCEEDED. Дождитесь, пока одна из запущенных генераций завершится, и запустите следующую.
Ошибки
У каждой есть машинный код в поле error и пояснение в message. Ошибки в настройках возвращают ещё и список допустимых значений, по нему видно, что править.
| Код | HTTP | Что означает |
|---|---|---|
| BEARER_REQUIRED | 401 | Нет заголовка Authorization или он не Bearer. |
| INVALID_TOKEN | 401 | Ключ не распознан, отозван или истёк. |
| TOKEN_OWNER_NOT_FOUND | 401 | Владелец ключа не найден. Выпустите ключ заново. |
| INSUFFICIENT_SCOPE | 403 | У ключа нет права на эту ручку. |
| ACCOUNT_BLOCKED | 403 | Аккаунт владельца ключа заблокирован. Причина в поле blockReason. |
| INVALID_CATEGORY | 400 | В фильтре каталога неизвестная категория. В ответе придёт список допустимых. |
| MODEL_REQUIRED | 400 | В запросе не указана модель. |
| UNKNOWN_MODEL | 400 | Такой модели нет в каталоге. |
| UNKNOWN_SETTING | 400 | У модели нет настройки с таким ключом. В ответе придёт список доступных. |
| INVALID_SETTING_VALUE | 400 | Значение вне допустимого списка или границ. |
| INVALID_DURATION | 400 | Такую длительность модель не принимает. |
| UNKNOWN_SLOT | 400 | У модели нет такого медиа-слота. |
| INVALID_MEDIA_URL | 400 | Ссылка не абсолютная https. |
| MEDIA_SLOT_LIMIT_EXCEEDED | 400 | В слоте больше файлов, чем принимает модель. Лимит слота указан в каталоге. |
| REQUEST_REJECTED | 400 | Запрос не прошёл общую проверку. Причина в поле code, например PROMPT_TOO_LONG_FOR_MODEL или PLAN_REQUIRED (модели нужен тариф выше вашего). |
| IMAGE_INPUT_NOT_SUPPORTED | 400 | Модель не принимает изображения, а они есть в запросе. |
| IMAGE_INPUT_REQUIRED | 400 | Модель меняет загруженное изображение, а в запросе его нет. |
| REFERENCE_INPUT_REQUIRED | 400 | Модели нужен хотя бы один референс: изображение или видео. |
| IMAGE_TO_VIDEO_NEEDS_IMAGE | 400 | Модель делает видео из изображения, а пришло видео. |
| INPUT_TYPE_MISMATCH | 400 | Модель работает с изображением и видео не принимает. |
| VIDEO_MODEL_NEEDS_IMAGE | 400 | Модели нужны и видео, и изображение. |
| INPUT_LIMIT_EXCEEDED | 400 | Файлов больше, чем принимает модель, или видео длиннее её лимита. |
| FILE_TOO_LARGE | 400 | Файл тяжелее лимита модели. Лимит указан в поле message. |
| SOURCE_FORMAT_UNSUPPORTED | 400 | Формат видео не поддерживается. Нужен MP4 или MOV. |
| SOURCE_CODEC_UNSUPPORTED | 400 | Модель не читает видео в этом кодеке. Нужен H.264 или HEVC. |
| SOURCE_RESOLUTION_TOO_HIGH | 400 | Разрешение видео выше, чем принимает модель. |
| SOURCE_TOO_MANY_FRAMES | 400 | В видео больше кадров, чем принимает модель. |
| BEEBLE_MASK_REQUIRED | 400 | Для замены объекта нужна маска. |
| BEEBLE_REFERENCE_REQUIRED | 400 | Для замены объекта нужен референс сцены. |
| BEEBLE_STYLE_INPUT_REQUIRED | 400 | Для нового фона нужен текст или референс сцены. |
| BEEBLE_KEYFRAME_REQUIRED | 400 | Не указан кадр, на котором нарисована маска. |
| BEEBLE_KEYFRAME_OUT_OF_RANGE | 400 | Кадра маски с таким номером в видео нет. |
| INPUT_MEDIA_PROBE_FAILED | 400 | Не удалось прочитать видео или звук по ссылке. Повторите запрос. |
| INSUFFICIENT_TOKENS | 402 | На балансе не хватает токенов. |
| PLAN_REQUIRED | 403 | Модели нет в списке моделей вашего тарифа. |
| GENERATION_NOT_FOUND | 404 | Генерации с таким id среди ваших нет. |
| GENERATION_INFLIGHT | 409 | Запрос с этим ключом идемпотентности уже выполняется. |
| RATE_LIMIT_EXCEEDED | 429 | Превышен лимит запросов в минуту. |
| DAILY_MODEL_QUOTA_EXHAUSTED | 429 | Дневной лимит этой модели на вашем тарифе исчерпан. |
| CONCURRENCY_LIMIT_EXCEEDED | 429 | Достигнут потолок одновременных генераций. В ответе есть поля limit и running. |
| CONCURRENCY_CHECK_UNAVAILABLE | 503 | Не удалось проверить потолок одновременных генераций. Повторите запрос. |
Когда API не нужен
Десяток генераций в неделю руками, и ключ ничего не упростит. В студии быстрее: видно результат, историю и подсказки по настройкам. Для повторяющихся цепочек без кода есть воркфлоу, для типовых операций подойдут экшены. Ключ имеет смысл, когда генерация встроена в ваш продукт или в регулярный процесс.
Выпустить ключ
Создаётся в кабинете за пару секунд и работает сразу. Стоимость генераций указана на странице тарифов; отдельной платы за доступ к API нет.
Профиль → API