Что такое публичный API#
Публичный API InPersona (/api/public/v1) даёт программный доступ ко всем генеративным моделям платформы: изображения, видео и LLM. Он устроен как у fal.ai или Replicate: вы отправляете задачу, получаете job id, а результат забираете поллингом или вебхуком.
- Base URL:
https://inpersona.ru/api/public/v1 - Авторизация: заголовок
Authorization: Bearer ips_…(API-ключ) - Цены: те же кредиты и те же тарифы, что и при генерации на сайте — API не дороже и не дешевле
- Доступность: тарифы Pro и Business (фича
api_access)
Если вам нужен доступ для AI-агентов (Claude, Cursor, Hermes) — посмотрите также MCP-сервер: это тот же функционал, но по протоколу MCP.
API-ключи#
Ключи выпускаются на странице Настройки → API-токены. Формат — ips_ + 43 символа; секрет показывается один раз при создании. У каждого ключа есть:
- Права (scopes):
read— чтение (поллинг, каталоги, баланс),generate— генерация (списывает кредиты). Для работы с API нужны оба. - Срок жизни — опциональная дата истечения (до 365 дней).
- Лимиты кредитов — опциональные потолки трат: за календарный месяц (UTC) и за всё время жизни ключа. При достижении лимита запросы отклоняются с ошибкой
token_spend_limit_exceeded(403); неудачные генерации возвращают кредиты и в кошелёк, и в лимит ключа. - Секрет подписи вебхуков (
whsec_…) — показывается вместе с ключом при создании и всегда доступен (и перевыпускается) на той же странице настроек. Нужен для проверки подписей вебхуков, см. ниже.
Ключ можно отозвать в любой момент — все клиенты с ним сразу начнут получать 401.
Быстрый старт#
# 1. Отправляем задачу
curl -s https://inpersona.ru/api/public/v1/images/generations \
-H "Authorization: Bearer ips_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Женская кожаная сумка на мраморном столе, мягкий утренний свет",
"model": "google/gemini-3-pro-image-preview-fast",
"aspect_ratio": "1:1",
"resolution": "high"
}'
# → 202 { "id": "img_abc123…", "status": "queued", "credits_spent": 1.5, … }
# 2. Поллим до status = completed (каждые 3–10 секунд)
curl -s https://inpersona.ru/api/public/v1/jobs/img_abc123… \
-H "Authorization: Bearer ips_ВАШ_КЛЮЧ"
# → { "status": "completed", "output": { "image_url": "https://s3.inpersona.ru/…" }, … }
Объект job#
Все генерации возвращают единый объект job:
{
"id": "img_5KpXk9…",
"kind": "image",
"status": "queued",
"credits_spent": 1.5,
"created_at": "2026-08-18T12:00:00Z",
"completed_at": null,
"output": null,
"error": null
}
id— префиксованный идентификатор:img_…(изображение),vid_…(видео),chat_…(LLM-вызов — возвращается в заголовке ответаX-InPersona-Job-Id, терминален сразу по завершении).status—queued→processing→completed|failed.output— приcompleted: для изображений{ image_url, thumbnail_url, width, height, seed }, для видео{ video_url, poster_url, width, height, duration_seconds, fps, file_size_bytes }.error— приfailed:{ code, message }. Кредиты за неудачную генерацию возвращаются автоматически.
Эндпоинты#
POST /images/generations#
Асинхронная генерация изображения. Возвращает 202 + job (img_…).
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
prompt | string | да | Текстовый промпт |
model | string | нет | Id модели из GET /models (по умолчанию google/gemini-3-pro-image-preview-fast) |
aspect_ratio | string | нет | 1:1 (по умолчанию), 3:4, 4:3, 16:9, 9:16 и др. |
resolution | string | нет | standard, high (по умолчанию), ultra |
reference_image_urls | string[] | нет | Публичные URL референсов (лимит зависит от модели — см. capabilities.max_references в GET /models). Загружайте через POST /files |
webhook_url | string | нет | HTTPS-URL для уведомления о завершении |
Примечание: разрешение ultra гейтится тарифом (фича high_resolution) — запрос выше вашего плана вернёт 403 feature_required.
POST /videos/generations#
Асинхронная генерация видео. Возвращает 202 + job (vid_…).
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
model | string | да | Id видеомодели из GET /models |
operation | string | нет | t2v (по умолчанию), i2v, r2v, v2v, frame_to_frame |
prompt / negative_prompt | string | зависит от модели | Описание сцены |
duration_seconds | integer | да | Длительность (допустимые значения — в capabilities модели) |
resolution | string | нет | 480p, 720p, 1080p, 4k — по capabilities |
aspect_ratio | string | нет | По умолчанию — первый поддерживаемый моделью |
audio_enabled | boolean | нет | Только для моделей с поддержкой аудио |
reference_image_urls | string[] | нет | Референсы (для i2v / r2v) |
frame_images | object[] | нет | [{ "url": "…", "position": "first" }] для frame_to_frame |
reference_video_urls | string[] | нет | Исходное видео для v2v |
provider_settings | object | нет | Пасстру для модель-специфичных настроек (до 4 КБ) |
auto_polish_enabled | boolean | нет | По умолчанию true: промпт автоматически дорабатывается перед отправкой. Передайте false, чтобы отправить промпт как есть |
webhook_url | string | нет | HTTPS-URL для уведомления |
Видео генерируется от десятков секунд до нескольких минут — поллите каждые 5–15 секунд или используйте вебхук.
GET /jobs/{id}#
Единый поллинг любой задачи по её id (img_… / vid_… / chat_…). Требует scope read.
POST /chat/completions#
OpenAI-совместимый доступ к LLM. Любой OpenAI SDK работает после замены base_url:
from openai import OpenAI
client = OpenAI(
base_url="https://inpersona.ru/api/public/v1",
api_key="ips_ВАШ_КЛЮЧ",
)
resp = client.chat.completions.create(
model="minimax/minimax-m2", # id из GET /models → llm_models
messages=[{"role": "user", "content": "Придумай слоган для бренда керамики"}],
stream=False, # stream=True — SSE-стриминг
)
print(resp.choices[0].message.content)
- Поддерживаются
model,messages,max_tokens(потолок 16384),temperature,response_format,stream. - Каждый ответ несёт поллящийся id задачи в заголовке
X-InPersona-Job-Id(chat_…, работает сGET /jobs/{id}). - Тарификация metered: реальная стоимость запроса у провайдера конвертируется в кредиты по внутреннему курсу $0.10 = 1 кредит. Для
stream: falseитог приходит вusage.cost_credits; дробные остатки копятся и списываются целыми кредитами. Если кошелёк не покрывает счёт целиком, списывается всё доступное, а остаток становится долгом — новые запросы получают 402 до пополнения. - Особенности стриминга: чанки проксируются как есть, поэтому
usage.cost_creditsв стрим НЕ подставляется (читайте job поX-InPersona-Job-Id); при ошибке провайдера посреди стрима приходит один чанкdata: {"error": …}и затемdata: [DONE]. Стримы ограничены 120 секундами и 2 конкурентными потоками на аккаунт (too_many_streams, 429). - Каталог доступных LLM — в
GET /models(секцияllm_models). Эндпоинт также отдаёт OpenAI-формат{"object":"list","data":[…]}, так чтоclient.models.list()работает.
POST /files — временное хранилище#
Загрузка входных файлов (референсы, кадры, аудио). Файлы хранятся 7 дней, затем автоматически удаляются — это хранилище для входных данных, а не архив. Результаты генераций хранятся постоянно.
Принимает одно из:
- multipart-поле
file; - JSON
{ "data": "data:image/jpeg;base64,…" }; - JSON
{ "url": "https://…" }— файл скачает сервер.
curl -s https://inpersona.ru/api/public/v1/files \
-H "Authorization: Bearer ips_ВАШ_КЛЮЧ" \
-F "file=@product.jpg"
# → 201 { "id": "file_42", "url": "https://s3.inpersona.ru/…", "expires_at": "2026-08-25T…" }
Возвращённый url сразу валиден в reference_image_urls, frame_images и других полях. Изображения нормализуются автоматически (HEIC/WebP → JPEG, до 4096px). Лимиты: изображения до 20 МБ, multipart-видео до 200 МБ; вариант url скачивается сервером с потолком 50 МБ. Не используйте URL после expires_at.
GET /files/{id} (scope read) возвращает метаданные файла; принимаются обе формы id — file_42 и 42.
GET /models#
Каталог моделей: image_models и video_models с полной матрицей capabilities (форматы, разрешения, длительности, лимиты референсов), llm_models — доступные LLM. Кэшируйте на время сессии.
GET /credits#
Баланс кошелька, полная таблица цен в кредитах (та же, что на сайте) и снапшот лимитов вашего ключа:
{
"balance": { "total": 250.0, "monthly": 200.0, "rollover": 30.0, "purchased": 20.0 },
"pricing": { "…": "…" },
"token": { "credit_limit_monthly": 100.0, "credits_spent_month": 12.5, "…": "…" }
}
Вебхуки#
Передайте webhook_url при создании задачи — по завершении (успех или ошибка) InPersona отправит POST:
{
"event": "job.completed",
"data": { "id": "img_…", "status": "completed", "output": { "…": "…" } }
}
Подпись. Каждая доставка подписана заголовком X-InPersona-Signature: t=<unix>,v1=<hex>, где v1 = HMAC-SHA256(secret, "<t>." + body). Секрет (whsec_…) привязан к вашему API-ключу — показывается при создании и всегда доступен (и перевыпускается) в Настройках → API-токены. Отклоняйте доставки, чей t отличается от текущего времени больше чем на ±5 минут (защита от replay); доверяйте только подписанному телу — остальные заголовки информационные. Проверка:
import hmac, hashlib
def verify(signature_header, body, secret):
parts = dict(p.split("=", 1) for p in signature_header.split(","))
expected = hmac.new(secret.encode(), f"{parts['t']}.{body}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
Ретраи. Успех — любой ответ 2xx (соединение за 5 с, ответ за 10 с). При неудаче — до 7 попыток суммарно с нарастающими паузами между ними (30 с → 2 мин → 10 мин → 30 мин → 2 ч → 6 ч), затем доставка помечается exhausted. Вебхуки — best-effort: источник истины всегда GET /jobs/{id}.
Требования к URL: только HTTPS, публичный хост (приватные/локальные адреса и сам inpersona.ru отклоняются).
Идемпотентность#
Все POST-эндпоинты принимают заголовок Idempotency-Key (8–255 символов; ключи вне диапазона молча игнорируются). Повтор с тем же ключом и телом вернёт закэшированный ответ вместо повторного списания; повтор с другим телом — ошибку idempotency_mismatch; конкурентный дубликат в полёте — 409 concurrent_request. Ответы с ошибкой освобождают ключ сразу, так что исправленный повтор с тем же ключом сработает. Ключи живут 24 часа. Для chat/completions работает только при stream: false.
Ошибки#
Единый формат:
{ "error": { "type": "invalid_request_error", "code": "model_not_found", "message": "…", "param": "model" } }
| HTTP | type | Типичные code |
|---|---|---|
| 401 | authentication_error | api_key_required, invalid_api_key |
| 402 | insufficient_credits | insufficient_credits (+ поля required, available) |
| 403 | permission_error | insufficient_scope, feature_required, token_spend_limit_exceeded, workflow_token_not_allowed |
| 404 | not_found_error | not_found |
| 409 | invalid_request_error | concurrent_request (тот же Idempotency-Key в полёте) |
| 422 | invalid_request_error | model_not_found, missing_parameter, invalid_operation, invalid_messages, messages_too_large, invalid_webhook_url, prompt_blocked, file_too_large, file_empty, unsupported_format, unsafe_url, upload_error, validation_error, idempotency_mismatch |
| 429 | rate_limit_error | rate_limited (+ заголовок Retry-After), upstream_rate_limited, too_many_streams |
| 500 | api_error | internal_error |
| 502 | api_error | upstream_error — ошибка провайдера модели |
Упавшие задачи несут error.code: "generation_failed" и человекочитаемый error.message.
Лимиты запросов#
На один ключ в минуту: 120 запросов всего по API, из них до 20 генераций (images + videos), до 10 вызовов chat/completions, до 20 загрузок файлов. При превышении — 429 с заголовком Retry-After.
Цены#
Каждая генерация стоит столько же кредитов, сколько на сайте, — таблица в GET /credits → pricing. LLM тарифицируется по фактической стоимости провайдера ($0.10 = 1 кредит). Кредиты за неудачные генерации возвращаются автоматически.