# pAIpe API: полная документация > Полный контекст для интеграции с pAIpe API. Актуальный машиночитаемый контракт: https://paipe.ru/openapi.yaml. Базовый адрес API: `https://api.paipe.ru/v1`. Аутентификация выполняется заголовком `Authorization: Bearer `. Пользовательские цены указаны в рублях. ## Chat Completions Источник: https://paipe.ru/docs/ai/chat-completions.md Для безопасной атрибуции расхода конечному пользователю используйте необязательное поле `user`; полный контракт описан в [end-user-attribution.md](https://paipe.ru/docs/ai/end-user-attribution.md). Для provider prompt caching и стабильной маршрутизации многошаговых workflow используйте `cache_control` и `session_id`/`X-Session-Id`. Полный безопасный контракт описан в [prompt-caching.md](https://paipe.ru/docs/ai/prompt-caching.md). Для анализа изображений используйте multipart `content`; форматы, лимиты, резервирование и требования конфиденциальности описаны в [multimodal-images.md](https://paipe.ru/docs/ai/multimodal-images.md). Для документов используйте native PDF content part; безопасный контракт описан в [pdf-inputs.md](https://paipe.ru/docs/ai/pdf-inputs.md). Для анализа аудио используйте raw-base64 `input_audio`; лимиты и отдельный тариф описаны в [audio-inputs.md](https://paipe.ru/docs/ai/audio-inputs.md). Для анализа видео используйте `video_url`; URL/base64-контракт, лимиты и требования к модели описаны в [video-inputs.md](https://paipe.ru/docs/ai/video-inputs.md). Для потоковой генерации речи используйте `modalities`, `audio` и `stream: true` по руководству [audio-outputs.md](https://paipe.ru/docs/ai/audio-outputs.md). Функции, structured outputs и reasoning описаны в [functions-and-structured-outputs.md](https://paipe.ru/docs/ai/functions-and-structured-outputs.md), а тарифицируемый серверный поиск — в [web-search.md](https://paipe.ru/docs/ai/web-search.md). Для чтения заранее разрешённых URL используйте [web-fetch.md](https://paipe.ru/docs/ai/web-fetch.md). `POST /v1/chat/completions` предоставляет OpenAI-совместимый интерфейс для обычной и потоковой генерации текста. Модель задаётся публичным идентификатором из `GET /v1/models`; количество моделей с теми же фильтрами возвращает `GET /v1/models/count`. Для управляемых конфигураций модель и параметры можно вынести в tenant-scoped пресет и передать `model: "@preset/{slug}"` либо поле `preset`. Параметры конкретного запроса имеют приоритет. Полный контракт создания версий, rollback и scopes описан в [presets.md](https://paipe.ru/docs/ai/presets.md). Конечные поставщики, доступные для выбранной модели, опубликованы в поле `providers` ответа `GET /v1/models`. Запрос может ограничить их через поле `provider`; сервер при этом всегда сохраняет обязательные правила приватности, надёжности и стоимости. ### Аутентификация и идемпотентность Передайте API-ключ со scope `inference:create`: ```http Authorization: Bearer Content-Type: application/json Idempotency-Key: order-2026-08-10-0001 ``` Ключ показывается только один раз. Для production можно ограничить его одним или несколькими каноническими IPv4/IPv6 CIDR. Запрос вне разрешённой сети получает тот же `401 invalid_api_key`, что и недействительный секрет: API не раскрывает, какой именно защитный контроль сработал. Для ротации создайте замену в кабинете, переключите интеграцию на новый секрет, проверьте рабочий трафик и только затем отзовите старый ключ. Во время перехода оба ключа действуют, поэтому ротация не требует остановки клиента. Права, срок и сетевые ограничения нового ключа фиксируются при создании и затем неизменяемы. `Idempotency-Key` должен содержать 8–128 символов из `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `-`. Если заголовок не передан, сервер создаст ключ и вернёт его в одноимённом response header. Для надёжных повторов клиенту следует всегда генерировать и сохранять ключ самостоятельно. Повторный запрос с уже использованным ключом не отправляется модели второй раз. Так как pAIpe не хранит ответы модели, содержимое успешного ответа не переигрывается: сервер вернёт `409 idempotency_replay_unavailable` и идентификатор исходного запроса. Использование того же ключа с другим телом вернёт `409 idempotency_conflict`. ### Пример запроса ```bash curl https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order-2026-08-10-0001" \ -d '{ "model": "paipe/text-pro", "messages": [ {"role": "system", "content": "Отвечай кратко."}, {"role": "user", "content": "Что такое идемпотентность?"} ], "provider": { "only": ["google-vertex", "azure"], "order": ["google-vertex", "azure"], "allow_fallbacks": true }, "max_completion_tokens": 256, "temperature": 0.2 }' ``` Поддерживаются поля `model`, `messages`, `max_tokens`, `max_completion_tokens`, `temperature`, `top_p`, `stop`, `tools`, `tool_choice`, `response_format`, `seed`, `frequency_penalty`, `presence_penalty`, `reasoning` и `provider`. Нельзя одновременно передавать `max_tokens` и `max_completion_tokens`. В `provider` доступны `only`, `order`, `allow_fallbacks` и `sort`. Значения `only` и `order` берутся из `providers[].id` каталога модели; если заданы оба поля, `order` должен быть подмножеством `only`. `sort` принимает `price`, `throughput` или `latency`. Настройки обработки данных, ценовой предел и допустимый общий список поставщиков задаёт pAIpe — передать или ослабить их из клиентского запроса нельзя. Фактический поставщик и безопасные сведения о попытках доступны после выполнения через `GET /v1/generation?id=...`. Сообщение может содержать строковый `content` либо до 64 частей `text`, `image_url`, `file`, `input_audio` и `video_url`. Изображения, PDF, аудио и видео разрешены только в сообщениях с ролью `user`; модель должна объявлять соответствующую входную modality. ### Потоковая выдача Передайте `"stream": true` и отключите буферизацию клиента: ```bash curl -N https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: stream-2026-08-11-0001" \ -d '{ "model": "paipe/text-pro", "messages": [{"role": "user", "content": "Ответь одним предложением"}], "max_completion_tokens": 256, "stream": true }' ``` Ответ имеет `Content-Type: text/event-stream`. Каждое событие содержит OpenAI-совместимый `chat.completion.chunk` с публичным идентификатором модели и `paipe.request_id`. Последнее JSON-событие содержит usage, после чего сервер отправляет `data: [DONE]`: ```text data: {"id":"chatcmpl_...","object":"chat.completion.chunk","model":"paipe/text-pro","choices":[{"index":0,"delta":{"content":"..."}}],"paipe":{"request_id":"..."}} data: {"id":"chatcmpl_...","object":"chat.completion.chunk","model":"paipe/text-pro","choices":[],"usage":{"prompt_tokens":24,"completion_tokens":18,"total_tokens":42},"paipe":{"request_id":"..."}} data: [DONE] ``` Если ошибка возникает после отправки HTTP 200, она приходит отдельным SSE- событием в обычном объекте `error`, затем поток закрывается маркером `[DONE]`. При разрыве клиентского соединения supervised-сессия прекращает пересылку контента, но дочитывает финальный usage и завершает точное списание. Тексты частичных ответов при этом не сохраняются. #### Явная отмена потока Для программной отмены используйте отдельный API-ключ со scope `inference:cancel` и UUID из response header `X-Request-ID` либо `paipe.request_id` любого SSE-события: ```bash curl -X POST "https://api.paipe.ru/v1/requests/$REQUEST_ID/cancel" \ -H "Authorization: Bearer $PAIPE_CANCELLATION_KEY" ``` Успешный вызов возвращает `202 Accepted`; повтор того же вызова идемпотентен: ```json { "id": "019fecc0-6cca-7e93-89f7-ad1cd5c06be3", "object": "inference.request.cancellation", "status": "cancellation_requested", "reconciliation_required": true, "requested_at": "2026-08-11T07:50:00Z" } ``` Отмена разрешена для активного Chat Completions, Responses или Image streaming-запроса своей организации. Чужой UUID возвращает такой же `404 request_not_found`, как несуществующий. Завершённый, непотоковый или уже остановленный без принятой отмены запрос возвращает `409 request_not_cancellable`. Принятая отмена останавливает supervised streaming-сессию и закрывает SSE событием `cancellation_requested`. Она намеренно не освобождает резерв сразу: внешняя модель могла уже принять запрос и начислить usage. Резерв остаётся активным до защищённой операторской сверки, исключая бесплатную частичную выдачу и двойное списание. ### Пример ответа ```json { "id": "chatcmpl_019fecc06cca7e9389f7ad1cd5c06be3", "object": "chat.completion", "created": 1786000000, "model": "paipe/text-pro", "choices": [ { "index": 0, "message": {"role": "assistant", "content": "..."} } ], "usage": { "prompt_tokens": 24, "completion_tokens": 18, "total_tokens": 42 }, "paipe": { "request_id": "019fecc0-6cca-7e93-89f7-ad1cd5c06be3" } } ``` `x-request-id` содержит тот же операционный идентификатор. Передавайте его поддержке при разборе инцидента. `RateLimit-Policy`, `RateLimit-Limit`, `RateLimit-Remaining` и `RateLimit-Reset` описывают текущее минутное окно организации. `RateLimit-Reset` содержит целое число секунд до следующего окна. При `429` и безопасно нормализованной временной недоступности API также возвращает `Retry-After`. Не повторяйте раньше этого срока; после него используйте exponential backoff с jitter и тот же `Idempotency-Key`. ### Биллинг До обращения к модели pAIpe резервирует на рублёвом балансе консервативную оценку максимальной стоимости. После успешного ответа резерв заменяется точным списанием по фактическому usage. Неиспользованный остаток резерва возвращается сразу. Если обычный запрос отклонён до выдачи результата, резерв освобождается полностью. Если уже начавшийся поток оборвался без проверяемого финального usage, резерв остаётся активным до операторской сверки — это исключает бесплатную частичную выдачу и ошибочное двойное списание. Для расчёта резерва и списания используется одна неизменяемая версия цены, даже если во время выполнения опубликован новый прайс. Текущие цены в рублях за миллион токенов доступны в `GET /v1/models`. Корпоративный администратор может ограничить каталог организации allowlist- политикой. `GET /v1/models`, расчёт цены и фактическая маршрутизация используют одну активную версию этой политики. Поэтому запрос скрытого идентификатора возвращает обычный `404 model_not_found` и не раскрывает, существует ли модель в общем каталоге. Организация может иметь версионируемую политику с лимитом запросов в минуту, числом одновременных генераций, максимальным размером ответа и дневным рублёвым бюджетом. Лимиты проверяются атомарно в PostgreSQL до обращения к модели; активные резервы входят в дневной бюджет, поэтому параллельные запросы не позволяют его превысить. Дневная граница рассчитывается по московскому времени (UTC+3). ### Ошибки До admission и резервирования организация может применять версионную политику чувствительного контента. Блокировка возвращает `403 content_guardrail_blocked`; ошибка безопасной проверки возвращает `503 content_guardrail_unavailable` с `Retry-After: 60`. Ни один из этих результатов не создаёт inference request и не изменяет баланс. Redact-правила заменяют совпадения до отправки модели; клиент получает обычный успешный ответ. Подробный контракт описан в [`content-guardrails.md`](https://paipe.ru/docs/ai/content-guardrails.md). Ошибки имеют единый формат: ```json { "error": { "message": "Insufficient account credit", "type": "billing_error", "code": "insufficient_credit", "request_id": "019fecc0-6cca-7e93-89f7-ad1cd5c06be3" } } ``` Основные статусы: | HTTP | Код | Значение | | --- | --- | --- | | 400 | `invalid_request` | Некорректное или неподдерживаемое поле | | 402 | `insufficient_credit` | Недостаточно средств для резерва | | 404 | `model_not_found` | Модель или цена недоступна организации | | 429 | `rate_limit_exceeded` | Исчерпан лимит запросов в минуту | | 429 | `concurrency_limit_exceeded` | Исчерпан лимит параллельных запросов | | 402 | `daily_spend_limit_exceeded` | Исчерпан дневной бюджет организации | | 402 | `api_key_spend_limit_exceeded` | Исчерпан лимит расходов текущего API-ключа | | 402 | `project_monthly_spend_limit_exceeded` | Исчерпан месячный бюджет проекта ключа | | 403 | `project_archived` | Проект ключа архивирован; выпустите ключ для активного проекта | | 429 | `max_output_tokens_exceeded` | Ответ превышает политику организации | | 409 | `request_in_progress` | Исходный запрос ещё выполняется | | 409 | `idempotency_replay_unavailable` | Запрос завершён, но ответ не хранится | | 409 | `idempotency_conflict` | Ключ использован с другим телом | | 404 | `request_not_found` | Запрос для отмены отсутствует в организации | | 409 | `request_not_cancellable` | Запрос нельзя отменить в текущем состоянии | | 429 | `upstream_rate_limited` | Временное ограничение мощности | | 502–504 | `upstream_*` | Безопасно нормализованная ошибка модели | Автоматический повтор после неопределённой сетевой ошибки не выполняется, поскольку он мог бы создать вторую платную генерацию. Клиент должен выяснить состояние по `request_id` или использовать новый ключ только после принятия решения на своей стороне. ### Конфиденциальность pAIpe не сохраняет тексты сообщений и ответы модели в таблице запросов. Хранятся только SHA-256 представления нормализованного запроса, выбранная версия цены, счётчики usage, финансовые ссылки, технические статусы и коды ошибок. Чувствительные параметры фильтруются из Phoenix-логов. Ответ API также проходит allowlist-фильтрацию: внутренние идентификаторы, provider metadata и system fingerprint не передаются клиенту, включая вложенные элементы choices. Машиночитаемый контракт и схемы ошибок опубликованы в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## API-ключи Источник: https://paipe.ru/docs/ai/api-key-management.md Проекты и их cost-center codes можно заранее создавать через [`/v1/projects`](https://paipe.ru/docs/ai/project-management.md), после чего передавать полученный `project_id` при выпуске рабочего ключа. API управления ключами предназначен для серверной автоматизации B2B-клиентов: CI/CD, выдачи краткоживущих ключей workloads, плановой ротации и немедленного отзыва. Он работает только в пределах одной организации и никогда не возвращает секреты уже существующих ключей. ### Создание management-ключа После недавнего повторного входа создайте ключ в защищённом веб-кабинете организации и выберите только scope `keys:manage`. Для него обязательно указать срок действия; проект выбирать нельзя. Секрет показывается один раз — сразу сохраните его в корпоративном менеджере секретов. Management-ключ нельзя создать или ротировать через API. Его выпуск требует повторной аутентификации не старше 10 минут. Создатель должен сохранять активное членство в организации и роль с правом `manage_api_keys`. Понижение роли, блокировка пользователя, выход из организации или блокировка организации немедленно лишают такой ключ полномочий управления. ```bash export PAIPE_KEY_MANAGER='pp_live_...' ``` Все ответы API управления ключами содержат `Cache-Control: no-store`. ### Создание рабочего ключа ```bash curl https://api.paipe.ru/v1/keys \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" \ -H "Content-Type: application/json" \ -d '{ "name": "production-inference", "scopes": ["models:read", "inference:create", "usage:read"], "expires_at": "2027-01-31T21:00:00Z", "project_id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "allowed_cidrs": ["203.0.113.10/32"], "limit_rub": "25000.00", "limit_reset": "monthly" }' ``` Ответ `201` содержит безопасные метаданные и одноразовое поле `key`: ```json { "data": { "id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d91", "object": "api_key", "name": "production-inference", "prefix": "a1b2c3d4e5", "scopes": ["models:read", "inference:create", "usage:read"], "status": "active", "allowed_cidrs": ["203.0.113.10/32"], "project": { "id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "name": "Production", "cost_center_code": "AI-PROD" }, "expires_at": "2027-01-31T21:00:00Z", "spend_limit": { "version": 1, "currency": "RUB", "amount": "25000", "reset_interval": "monthly", "effective_from": "2026-08-11T20:00:00Z" } }, "key": "pp_live_a1b2c3d4e5_..." } ``` Допустимы только рабочие scopes: `models:read`, `inference:create`, `inference:cancel`, `usage:read`, `billing:read` и `presets:read`. Организационные management scopes `keys:manage` и `presets:write` через API не делегируются. Срок действия обязателен и ограничен 366 днями. Неизвестные поля отклоняются. `limit_rub` передаётся десятичной строкой, а не JSON float, и хранится точно до нанорубля. `limit_reset` принимает `daily`, `weekly`, `monthly` или `lifetime`. Оба поля необязательны при создании, но при наличии одного второе обязательно. ### Изменение лимита расходов ```bash curl -X PATCH \ "https://api.paipe.ru/v1/keys/018f3a8f-4f67-7b21-a84d-09f18a1b6d91" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" \ -H "Content-Type: application/json" \ -d '{ "limit_rub": "50000.00", "limit_reset": "weekly", "reason": "Увеличение лимита для производственной нагрузки" }' ``` Изменение не перезаписывает историю: сервер создаёт следующую неизменяемую версию с автором, причиной и временем активации. Дневная, недельная и месячная границы рассчитываются по `Europe/Moscow`; неделя начинается в понедельник. В admission учитываются уже списанные расходы окна, активные резервы и оценка нового запроса. Поэтому параллельные запросы не могут превысить лимит за счёт гонки. При превышении inference API возвращает `402 api_key_spend_limit_exceeded` до обращения к внешнему поставщику. Чтобы явно отключить ограничение и сохранить это решение в истории, передайте `limit_rub: null`, `limit_reset: null` и причину. Лимиты не назначаются ключам с организационными management scopes. При zero-downtime rotation действующая версия автоматически наследуется преемником. Текущий рабочий ключ может получить собственное использование, активный лимит, зарезервированную сумму, остаток и время сброса через `GET /v1/key`. ### Список метаданных ```bash curl "https://api.paipe.ru/v1/keys?include_revoked=false&limit=100&offset=0" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" ``` Ответ возвращает `object: list`, массив `data` и заголовки `X-Total-Count`, `X-Page-Limit`, `X-Page-Offset`. В нём нет plaintext-секретов и хешей. По умолчанию отозванные ключи скрыты; для аудита передайте `include_revoked=true`. ### Zero-downtime rotation ```bash curl -X POST \ "https://api.paipe.ru/v1/keys/018f3a8f-4f67-7b21-a84d-09f18a1b6d91/rotate" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" \ -H "Content-Type: application/json" \ -d '{"expires_at":"2027-02-28T21:00:00Z"}' ``` Преемник наследует scopes, проект и CIDR исходного ключа. Новый секрет снова возвращается один раз. Исходный ключ остаётся активным, поэтому порядок смены: 1. Создайте преемника. 2. Сохраните новый секрет и обновите workloads. 3. Проверьте успешные запросы с новым ключом. 4. Отзовите старый ключ. Для overlap разрешено ровно одно временное место сверх штатного лимита активных ключей. Повторная ротация исходного ключа до отзыва его активного преемника возвращает `409 rotation_already_started`. ### Немедленный отзыв ```bash curl -X DELETE \ "https://api.paipe.ru/v1/keys/018f3a8f-4f67-7b21-a84d-09f18a1b6d91" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" ``` Операция идемпотентна. После ответа `200` старый секрет больше не проходит аутентификацию. UUID ключа другой организации не раскрывает его существование и возвращает `404 api_key_not_found`. ### Ошибки и эксплуатационные правила | HTTP | code | Действие | | --- | --- | --- | | 400 | `management_scope_cannot_be_delegated` | Создайте или ротируйте management-ключ (`keys:manage` / `presets:write`) вручную в кабинете | | 400 | `managed_key_expiry_too_long` | Укажите срок не более 366 дней | | 400 | `invalid_spend_limit` | Передайте согласованную пару `limit_rub` / `limit_reset` | | 400 | `management_key_spend_limit_unsupported` | Выберите рабочий inference-ключ | | 403 | `permission_denied` | Проверьте активность создателя и его текущую роль | | 404 | `api_key_not_found` | Проверьте UUID внутри текущей организации | | 409 | `rotation_already_started` | Завершите текущую ротацию и отзовите старый ключ | | 409 | `api_key_limit_reached` | Отзовите неиспользуемый ключ либо завершите overlap | Не передавайте management-секрет в браузер, мобильное приложение или сборочные логи. Ограничьте его исходящими CIDR, задайте короткий срок, регулярно ротируйте в кабинете и используйте отдельный ключ на каждую систему автоматизации. --- ## Проекты и бюджеты Источник: https://paipe.ru/docs/ai/project-management.md Projects API позволяет B2B-клиенту программно управлять рабочими пространствами, центрами затрат и месячными бюджетами, не заходя в кабинет. Проект остаётся внутри одной организации и используется для неизменяемой атрибуции API-ключей, расходов, аналитики и финансовых экспортов. ### Доступ и модель безопасности Все операции требуют серверный management-ключ с единственным scope `keys:manage`. Такой ключ создаётся участником с правом управления API-ключами в защищённом кабинете после недавней повторной аутентификации. При каждом запросе Paipe заново проверяет членство, текущую роль и разрешение конкретной операции. Owner и admin могут создавать, бюджетировать и архивировать проекты; developer может только читать их. Понижение до роли без `manage_api_keys` или удаление участника немедленно прекращает доступ без ожидания срока действия ключа. Management-ключ действует на всю организацию. Храните его в серверном vault, ограничьте исходящими CIDR, задайте короткий срок и не передавайте в браузер, мобильное приложение, логи или пользовательские workloads. ### Создание проекта ```bash curl -X POST https://api.paipe.ru/v1/projects \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" \ -H "Content-Type: application/json" \ -d '{ "name": "Production agents", "cost_center_code": "AI-PROD" }' ``` `cost_center_code` уникален внутри организации, приводится к верхнему регистру и содержит 2–32 символа: латинские буквы, цифры, точку, `_` или `-`. Ответ `201` содержит provider-neutral объект проекта. Его `id` можно передать как `project_id` при создании рабочего API-ключа. ### Список и чтение ```bash curl "https://api.paipe.ru/v1/projects?include_archived=false&limit=100&offset=0" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" curl "https://api.paipe.ru/v1/projects/$PROJECT_ID" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" ``` Список возвращает `object: list`, массив `data` и заголовки `X-Total-Count`, `X-Page-Limit`, `X-Page-Offset`. `limit` ограничен диапазоном 1–200, `offset` — 0–10000. Архивные проекты скрыты по умолчанию. Все ответы имеют `Cache-Control: no-store`. UUID другой организации и отсутствующий UUID дают одинаковый `404 project_not_found`, поэтому API не раскрывает существование чужих ресурсов. ### Месячный бюджет ```bash curl -X PATCH "https://api.paipe.ru/v1/projects/$PROJECT_ID/budget" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" \ -H "Content-Type: application/json" \ -d '{ "limit_rub": "125000.500000001", "reason": "Утверждён бюджет production-нагрузки на квартальном комитете" }' ``` Сумма передаётся только точной положительной десятичной строкой RUB с точностью до 9 знаков после запятой. Float не принимается. Каждое изменение добавляет неизменяемую версию политики с автором, причиной и временем активации; история не перезаписывается. Расчёт месячного окна выполняется по `Europe/Moscow`, а admission учитывает уже списанные расходы, активные резервы и оценку нового запроса под блокировкой проекта. Для явного отключения ограничения создайте новую версию: ```json { "limit_rub": null, "reason": "Временный безлимит согласован финансовым директором" } ``` ### Архивирование ```bash curl -X DELETE "https://api.paipe.ru/v1/projects/$PROJECT_ID" \ -H "Authorization: Bearer $PAIPE_KEY_MANAGER" ``` DELETE выполняет логическое архивирование, фиксируя автора и время. Финансовая история и атрибуция не удаляются. Перед архивированием отзовите все активные API-ключи проекта; иначе API вернёт `409 project_has_active_api_keys`. Архивированный проект больше не принимает inference-запросы. ### Ошибки | HTTP | code | Действие | | --- | --- | --- | | 400 | `invalid_project` | Исправьте имя или уникальный cost-center code | | 400 | `invalid_limit_rub` | Передайте `null` или положительную decimal-строку с точностью до 9 знаков | | 400 | `unknown_parameter` | Удалите поля, которых нет в OpenAPI-контракте | | 403 | `insufficient_scope` | Используйте management-ключ с `keys:manage` | | 403 | `permission_denied` | Проверьте активность и текущую роль создателя management-ключа | | 404 | `project_not_found` | Проверьте UUID внутри текущей организации | | 409 | `project_has_active_api_keys` | Отзовите активные ключи проекта | | 409 | `project_archived` | Создайте новый активный проект | Полный машиночитаемый контракт, модели ответов и generated SDK operation IDs опубликованы в [OpenAPI 3.1](https://paipe.ru/openapi.yaml). --- ## Баланс и текущий ключ Источник: https://paipe.ru/docs/ai/credits-and-current-key.md Два read-only endpoint позволяют серверным интеграциям контролировать расходы без входа в кабинет. Все суммы передаются точными decimal strings в рублях, а ответы содержат `Cache-Control: no-store`. ### Текущий ключ `GET /v1/key` доступен любому действующему API-ключу и не требует отдельного scope: ```bash curl https://api.paipe.ru/v1/key \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Ответ содержит: - безопасные `id`, `prefix`, название, scopes, проект и сроки действия; - признак сетевого ограничения без раскрытия разрешённых CIDR; - settled usage самого ключа за день, неделю, месяц и всё время; - актуальные RPM, concurrency и output-token ceilings организации; - live-состояние текущего RPM-окна: `interval`, `limit`, `used`, `remaining` и `resets_at`; - собственную версионируемую политику расходов ключа: точный RUB-лимит, период, settled/зарезервированную/committed сумму, остаток и время сброса. Секрет, его хеш, пользователь-создатель, разрешённые сети, prompts, outputs, внутренний маршрут и поставщик не возвращаются. Дневные периоды и недельные/месячные usage-окна считаются в `Europe/Moscow`; неделя начинается в понедельник. Поле `usage` включает только финально рассчитанные успешные запросы. `spend_limit.reserved` дополнительно показывает активные резервы этого ключа, чтобы интеграция видела тот же committed amount, который используется admission-проверкой. При отсутствии истории политик `spend_limit` равен `null`; явно отключённая версия имеет `amount` и `reset_interval`, равные `null`. Текущая активность других ключей и финансовые лимиты организации здесь намеренно не раскрываются. ### Доступная финансовая ёмкость `GET /v1/credits` требует scope `billing:read`: ```bash curl https://api.paipe.ru/v1/credits \ -H "Authorization: Bearer $PAIPE_BILLING_KEY" ``` Пример prepaid-ответа организационного ключа: ```json { "data": { "object": "credit.capacity", "generated_at": "2026-08-11T10:30:00Z", "currency": "RUB", "scope": { "organization_id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "project_id": null }, "billing_mode": "prepaid", "credit_suspended": false, "available_amount": "250000", "organization_capacity": { "cash_balance": "250000", "credit_limit": "0", "credit_exposure": "0" }, "project_budget": null } } ``` Для postpaid `available_amount` учитывает собственный RUB-баланс, остаток одобренной кредитной линии, задолженность и активные резервы. При просрочке `credit_suspended` становится `true`: новая postpaid-ёмкость исключается, но положительный собственный баланс остаётся доступным. ### Изоляция проекта Если ключ привязан к проекту, endpoint не раскрывает общий баланс, кредитный лимит или задолженность организации. `organization_capacity` будет `null`, а `available_amount` станет меньшим из: - фактической доступной ёмкости организации; - остатка месячного бюджета проекта. `project_budget` содержит период, версию политики, settled расходы, активные резервы, общий committed amount и остаток. Если лимит не установлен, `limit_amount` и `remaining_amount` равны `null`, но фактические расходы всё равно отображаются. ### Рекомендуемые ключи мониторинга Создавайте отдельный organization-level ключ только с `billing:read`, коротким сроком действия и CIDR-ограничением. Не используйте для мониторинга `keys:manage`: он имеет более широкие полномочия и предназначен исключительно для автоматизации жизненного цикла ключей. --- ## Использование и журнал Источник: https://paipe.ru/docs/ai/usage.md Сводку можно ограничить одним `end_user_ref`, полученным из inference-ответа. Сырые идентификаторы не принимаются; см. [end-user-attribution.md](https://paipe.ru/docs/ai/end-user-attribution.md). `GET /v1/usage` возвращает агрегированное использование и фактически списанную сумму. Эндпоинт требует API-ключ со scope `usage:read`; организация и проектная область определяются только по аутентифицированному ключу и не принимаются из query или тела запроса. Ключ, неизменяемо привязанный к проекту, видит только расходы этого проекта. Ключ без проекта сохраняет обратную совместимость и видит всю организацию. Чтобы получить раздельную отчётность, создавайте отдельные ключи для проектов; нельзя превратить уже выпущенный ключ из организационного в проектный. ### Запрос ```bash curl "https://api.paipe.ru/v1/usage?days=30" \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Параметр `days` необязателен, принимает целое число от 1 до 366 и по умолчанию равен 30. Период начинается в 00:00 по московскому времени первого включённого дня и заканчивается текущим моментом. ### Ответ ```json { "object": "usage.summary", "period": {"days": 30, "timezone": "Europe/Moscow"}, "scope": { "organization_id": "90ae4b2b-17dc-42fd-a66a-15d8c1cacdc7", "project_id": "b137c08f-e8cc-40cb-9bf1-b68dca85e5f2", "end_user_ref": null }, "requests": 1842, "tokens": { "input": 2700000, "output": 640000, "total": 3340000 }, "images": { "output": 12, "references": 3, "output_pixels": 12582912, "output_megapixels": "12.582912" }, "server_tools": {"web_search_requests": 46}, "speech": {"input_characters": 4200}, "video": {"seconds": 35}, "billed": { "currency": "RUB", "amount": "1725.84" } } ``` `billed.amount` — десятичная строка, а не JSON float. Она строится из точного целочисленного значения в nanorub и не теряет точность при сериализации. Учитываются только успешно завершённые и списанные inference-запросы. `scope.project_id` равен `null` для организационного ключа. `video.seconds` содержит оплаченные секунды асинхронной генерации видео. ### Метаданные отдельной генерации `GET /v1/generation?id=` позволяет сверить конкретный запрос по UUID из заголовка `X-Request-ID` или поля `paipe.request_id` inference-ответа: ```bash curl "https://api.paipe.ru/v1/generation?id=$REQUEST_ID" \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Ответ не содержит prompt, output или upstream-идентификаторы. Он показывает запрошенный и фактический конечный поставщик, безопасную историю попыток и этапы времени выполнения. Проектный ключ может читать только генерации своего проекта, а организационный — всей своей организации. Недоступный запрос и несуществующий UUID намеренно возвращают одинаковый `404 request_not_found`. ```json { "data": { "id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "object": "generation", "operation": "chat_completion", "model": "paipe/text-pro", "status": "succeeded", "streamed": false, "created_at": "2026-08-11T09:30:00Z", "started_at": "2026-08-11T09:30:00Z", "completed_at": "2026-08-11T09:30:01Z", "latency_ms": 1000, "provider": { "status": "ready", "id": "google-vertex", "name": "Google Vertex", "requested": ["google-vertex", "azure"], "data_region": "europe-west4", "service_tier": null, "finish_reason": "stop", "native_finish_reason": "STOP", "responses": [ { "provider": "Google Vertex", "status": 200, "latency_ms": 420, "generation_ms": 510, "error_code": null } ] }, "timing": { "total_ms": 1000, "routing_ms": 24, "provider_ms": 420, "moderation_ms": null, "generation_ms": 510, "throughput_tokens_per_second": 70.59 }, "scope": { "organization_id": "90ae4b2b-17dc-42fd-a66a-15d8c1cacdc7", "project_id": "b137c08f-e8cc-40cb-9bf1-b68dca85e5f2", "project_name": "Production", "cost_center_code": "AI-PROD", "end_user_ref": "eu_qZ7RkW8QzOJK6c88oTFxMs3ePip0EkGs5o-lpFVAsRg" }, "tokens": { "input": 120, "output": 36, "cached_input": 80, "cache_write": 0, "reasoning": 12, "total": 248 }, "images": { "output": 0, "references": 0, "output_pixels": 0, "output_megapixels": "0" }, "server_tools": {"web_search_requests": 2}, "video": {"seconds": 0}, "billed": {"currency": "RUB", "amount": "0.1842"}, "failure": null } } ``` Состояние `provider.status=pending` означает, что безопасные сведения ещё собираются; `unavailable` — что поставщик не предоставил их после завершения. Для незавершённого или не списанного запроса `billed` равен `null`. Для безопасной поддержки ошибки нормализуются до `request_failed` либо `settlement_review_required` без раскрытия ответа внешнего поставщика. Ответ всегда содержит `Cache-Control: no-store`. ### Журнал генераций `GET /v1/generations` возвращает журнал безопасных метаданных в обратном хронологическом порядке. Он предназначен для сверки, FinOps-выгрузок и работы службы поддержки без доступа к prompt или output. Эндпоинт использует тот же scope `usage:read` и ту же неизменяемую организационную/проектную границу ключа, что и сводка использования. ```bash curl --get "https://api.paipe.ru/v1/generations" \ -H "Authorization: Bearer $PAIPE_API_KEY" \ --data-urlencode "from=2026-08-01T00:00:00Z" \ --data-urlencode "to=2026-09-01T00:00:00Z" \ --data-urlencode "status=succeeded" \ --data-urlencode "limit=100" ``` Доступные фильтры: `from`, `to`, `status`, `operation`, точный публичный `model`, `project_id`, `api_key_id` и непрозрачный `end_user_ref`. Период не может превышать 366 дней; без дат используется окно последних 30 дней. `limit` принимает значения от 1 до 1000. ```json { "object": "list", "data": [ { "id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "object": "generation", "api_key": { "id": "3e27dc8d-f08e-4d37-8534-a60fca9e4235", "prefix": "paipe_live_ab12" }, "operation": "chat_completion", "model": "paipe/text-pro", "status": "succeeded", "billed": {"currency": "RUB", "amount": "0.1842"} } ], "first_id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "last_id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "has_more": true, "cursor": "opaque-signed-cursor", "meta": { "time_range": { "from": "2026-08-01T00:00:00Z", "to": "2026-09-01T00:00:00Z" }, "filters": { "status": "succeeded", "operation": null, "model": null, "project_id": null, "api_key_id": null, "end_user_ref": null } } } ``` Элементы `data` имеют полный формат `generation`, показанный выше, и дополнительно содержат безопасные `api_key.id` и `api_key.prefix`. Для следующей страницы повторите те же фильтры и передайте значение `cursor`. Если даты были опущены в первом запросе, передавать их позднее не нужно: исходное окно хранится в подписанном курсоре. Курсор действует 24 часа и не может быть использован с другой организацией, проектом или набором фильтров. ### Ошибки | HTTP | Код | Значение | | --- | --- | --- | | 400 | `invalid_days` | `days` не является целым числом от 1 до 366 | | 400 | `generation_id_required` | Для `/v1/generation` не передан параметр `id` | | 400 | `invalid_cursor` | Курсор истёк, повреждён или использован с другой областью/фильтрами | | 400 | `invalid_time_range` | Период журнала некорректен или превышает 366 дней | | 401 | `invalid_api_key` | Ключ отсутствует, недействителен, истёк или отозван | | 403 | `insufficient_scope` | У ключа нет scope `usage:read` | | 404 | `request_not_found` | UUID не существует либо недоступен организации/проекту ключа | Полная схема находится в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). Для группировки по времени, проекту, модели, операции и статусу используйте [Analytics Query API](https://paipe.ru/docs/ai/analytics.md). Он сохраняет ту же область организации или проекта ключа и возвращает точные RUB-значения без пользовательского контента. --- ## Responses и Embeddings Источник: https://paipe.ru/docs/ai/responses-and-embeddings.md Оба endpoint принимают необязательное поле `user` по безопасному контракту из [end-user-attribution.md](https://paipe.ru/docs/ai/end-user-attribution.md). Responses поддерживает `cache_control` и `session_id`/`X-Session-Id`; подробности валидации, ZDR и биллинга приведены в [prompt-caching.md](https://paipe.ru/docs/ai/prompt-caching.md). Embeddings этот механизм не использует. Responses также принимает `input_image`; безопасный контракт приведён в [multimodal-images.md](https://paipe.ru/docs/ai/multimodal-images.md). Контракт клиентских функций, `text.format`, reasoning и защита от неучтённых server tools описаны в [functions-and-structured-outputs.md](https://paipe.ru/docs/ai/functions-and-structured-outputs.md). Тарифицируемый серверный поиск описан отдельно в [web-search.md](https://paipe.ru/docs/ai/web-search.md), а чтение страниц по доменному allowlist — в [web-fetch.md](https://paipe.ru/docs/ai/web-fetch.md). `POST /v1/responses` и `POST /v1/embeddings` используют тот же API-ключ со scope `inference:create`, рублёвый прайс, лимиты организации, атомарный резерв и фактическое списание, что и Chat Completions. Для Responses доступен тот же ограниченный выбор конечного поставщика через поле `provider`; Embeddings пока использует автоматический выбор pAIpe. Все операции на этой странице используют организационную политику чувствительного контента до admission и резервирования. `block` возвращает `403 content_guardrail_blocked`, а безопасно не завершившаяся проверка — `503 content_guardrail_unavailable`. Проверяемые текстовые поля и исключения перечислены в [`content-guardrails.md`](https://paipe.ru/docs/ai/content-guardrails.md). ### Responses Минимальный запрос: ```bash curl https://api.paipe.ru/v1/responses \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: response-2026-08-11-0001" \ -d '{ "model": "paipe/text-pro", "input": "Кратко объясни атомарный биллинг", "provider": { "only": ["google-vertex", "azure"], "sort": "latency" }, "max_output_tokens": 256 }' ``` `input` принимает непустую строку или до 256 структурированных элементов `message` и `function_call_output`. Поддерживаются `instructions`, `tools`, `tool_choice`, `text`, `reasoning`, `temperature`, `top_p`, `parallel_tool_calls` и `truncation`. В `message.content` допустимы части `input_text` и `input_image`; изображения разрешены только для роли `user` и image-capable модели. Responses остаётся stateless: `store`, `background`, `previous_response_id` и прочие неподдерживаемые поля отклоняются до резервирования и обращения к модели. В `provider` разрешены только `only`, `order`, `allow_fallbacks` и `sort`; серверные правила обработки данных, стоимости и надёжности изменить нельзя. Ответ получает публичный `resp_…`, публичный alias модели и `paipe.request_id`. Верхнеуровневые служебные metadata, исходные идентификаторы ответа и вложенные provider metadata удаляются. Текст, tool calls и безопасные аннотации сохраняют совместимую структуру. #### Responses streaming Добавьте `"stream": true` и используйте SSE-клиент или `curl -N`: ```bash curl -N https://api.paipe.ru/v1/responses \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: response-stream-2026-08-11-0001" \ -d '{ "model": "paipe/text-pro", "input": "Кратко объясни атомарный биллинг", "max_output_tokens": 256, "stream": true }' ``` Gateway передаёт только явно поддержанные provider-neutral события: lifecycle, output item/content part, text/refusal delta, reasoning delta и аргументы caller-executed function calls. В каждом событии исходный response/item ID заменяется стабильным публичным ID запроса; routing metadata, upstream model и диагностика поставщика удаляются. Финальное событие `response.completed` либо `response.incomplete` удерживается до проверки полного ответа, trustworthy usage и атомарного RUB capture. Затем следует `data: [DONE]`. При неизвестном событии, повреждённом JSON, provider error или отсутствии terminal event поток завершается нормализованной ошибкой, а активный резерв сохраняется для сверки, поскольку delta уже могла быть доставлена. Повторять такой запрос с новым `Idempotency-Key` нельзя. Активный поток можно отменить через `POST /v1/requests/{request_id}/cancel` ключом со scope `inference:cancel`. Отмена идемпотентна и также оставляет резерв в reconciliation до подтверждения provider usage. ### Embeddings Пакетный запрос: ```bash curl https://api.paipe.ru/v1/embeddings \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: embedding-2026-08-11-0001" \ -d '{ "model": "paipe/text-embedding", "input": ["Первый документ", "Второй документ"], "encoding_format": "float" }' ``` `input` принимает одну непустую строку, массив до 256 непустых строк либо массив мультимодальных объектов. Для совместного embedding текста и изображения: ```json { "model": "paipe/multimodal-embedding", "input": [{ "content": [ {"type": "text", "text": "Эталонная схема"}, { "type": "image_url", "image_url": {"url": "https://cdn.example.ru/architecture.png"} } ] }], "encoding_format": "float" } ``` Изображение задаётся публичным HTTPS URL без credentials/fragment или ограниченным data URL PNG, JPEG, WebP либо GIF. Действуют те же SSRF-проверки и лимит 700 000 декодированных байт, что для Chat/Responses: до 16 изображений, 64 частей в одном input и 256 частей на запрос. Выбранная модель должна иметь `image` в `input_modalities` и `embedding`/`embeddings` в `output_modalities`. При наличии изображения gateway консервативно резервирует цену полного контекста, потому что точная токенизация заранее неизвестна, а после ответа атомарно списывает только фактические input tokens. Размер JSON ограничен 1 MiB. Поддерживаются положительный `dimensions`, `input_type` и `user`; формат в текущей версии всегда `float`. Token arrays и `encoding_format: base64` отклоняются явно. Сервис проверяет, что upstream вернул непустой массив числовых векторов и проверяемый usage. Списание рассчитывается по фактическим input tokens и зафиксированной версии рублёвой цены. В клиентский ответ входят только векторы, индексы, публичная модель, usage и `paipe.request_id`. ### Idempotency и ошибки `Idempotency-Key` имеет общий namespace организации для всех inference endpoint’ов. Тип операции включён в SHA-256 digest запроса, поэтому попытка использовать один ключ для Chat Completions, Responses и Embeddings вернёт `409 idempotency_conflict`, а не запустит вторую платную операцию. Успешный ответ возвращает `Idempotency-Key` и `X-Request-ID`. Формат ошибок, статусы 400/402/404/409/429/502–504 и правила безопасного повтора описаны в [Chat Completions API](https://paipe.ru/docs/ai/chat-completions.md). Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Функции и JSON Источник: https://paipe.ru/docs/ai/functions-and-structured-outputs.md Публичные API `POST /v1/chat/completions` и `POST /v1/responses` поддерживают клиентские функции, JSON Schema-ответы и управление reasoning. Эти возможности доступны только у моделей, которые объявляют соответствующее значение в `supported_parameters` ответа `GET /v1/models`. ### Функции Разрешены только функции, которые выполняет приложение клиента. Платформа возвращает аргументы вызова, клиент исполняет функцию в своей доверенной среде и передаёт результат следующим запросом. Имя функции содержит 1–64 символа из `A-Z`, `a-z`, `0-9`, `_`, `-`; имена в одном запросе уникальны. Chat Completions использует вложенный OpenAI-совместимый формат: ```json { "tools": [ { "type": "function", "function": { "name": "lookup_invoice", "description": "Найти счёт по номеру", "strict": true, "parameters": { "type": "object", "properties": {"number": {"type": "string"}}, "required": ["number"], "additionalProperties": false } } } ], "tool_choice": { "type": "function", "function": {"name": "lookup_invoice"} } } ``` Responses использует плоское определение: ```json { "tools": [ { "type": "function", "name": "lookup_invoice", "description": "Найти счёт по номеру", "strict": true, "parameters": { "type": "object", "properties": {"number": {"type": "string"}}, "required": ["number"], "additionalProperties": false } } ], "tool_choice": {"type": "function", "name": "lookup_invoice"} } ``` Допустимо до 128 функций. `tool_choice` также принимает `none`, `auto` или `required`; именованный выбор обязан ссылаться на функцию из того же запроса. Описание ограничено 4096 байт, а каждая JSON Schema — 64 КиБ, 16 уровнями вложенности и 2048 JSON-узлами. ### Structured outputs Для Chat Completions передайте `response_format`: ```json { "response_format": { "type": "json_schema", "json_schema": { "name": "invoice_result", "strict": true, "schema": { "type": "object", "properties": {"found": {"type": "boolean"}}, "required": ["found"], "additionalProperties": false } } } } ``` Для Responses тот же смысл задаётся через `text.format`; поля `name`, `schema`, `strict` находятся непосредственно внутри `format`. Также поддерживаются `{"type":"text"}` и `{"type":"json_object"}`. JSON-режимы требуют `structured_outputs` или `response_format` в возможностях выбранной модели. ### Reasoning и биллинг `reasoning` принимает только `effort`, `max_tokens`, `exclude`, `enabled`. `effort` — одно из `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Поля `effort` и `max_tokens` взаимоисключающие, а `max_tokens` должен быть меньше общего лимита вывода. Модель должна объявлять параметр `reasoning`. Reasoning-токены входят в зарезервированный лимит output и после ответа списываются по фактическому usage и опубликованной рублёвой цене. Настройка не создаёт отдельной скрытой услуги. ### Server-managed tools Платформа поддерживает отдельно тарифицируемый server-managed инструмент `paipe:web_search`. Для него опубликована рублёвая цена, резерв строится по `max_uses`, а списание и сверка выполняются по фактическому `usage.server_tool_use.web_search_requests`. Полный контракт и пример приведены в [web-search.md](https://paipe.ru/docs/ai/web-search.md). Кроме него доступен `paipe:web_fetch`: платформа принудительно использует direct-fetch без отдельной платы, требует `allowed_domains` и резервирует `max_uses * max_content_tokens` как возможный входной контекст. Списание идёт только по фактическим токенам модели. Контракт и модель угроз приведены в [web-fetch.md](https://paipe.ru/docs/ai/web-fetch.md). Другие типы (`web_search`, `web_search_preview`, `web_fetch`, плагины, провайдерские маршруты и произвольные server-managed tools) по-прежнему отклоняются до резервирования и отправки модели с кодом `400 unpriced_provider_extension`. Другие важные ошибки: - `400 invalid_request` — неверная структура, неизвестное вложенное поле, слишком большая схема или ссылка на отсутствующую функцию; - `400 unsupported_model_capability` — выбранная модель не объявляет нужные `tools`, `web_search`, structured outputs или `reasoning`. Полный машинно-читаемый контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Пресеты Источник: https://paipe.ru/docs/ai/presets.md Пресет отделяет конфигурацию модели от клиентского кода. Организация может изменить публичную модель, системную инструкцию или параметры генерации, не выпуская новую версию интеграции. Каждая конфигурация сохраняется как неизменяемая версия, а inference-запрос фиксирует ID фактически использованной версии. Пресеты tenant-scoped: одинаковый slug в разных организациях относится к разным объектам. В публичном контракте хранятся только публичные ID моделей; сведения о поставщиках и внутренних маршрутах не возвращаются. ### Scopes - `presets:read` — список и чтение конфигурации с историей версий; - `presets:write` — создание версии, rollback и архивирование. `presets:write` — изолированный организационный management scope. Такой ключ имеет обязательный срок действия, не привязывается к проекту и не совмещается с inference или read scopes. Выпустить его можно только после недавней аутентификации в веб-кабинете; management API не может делегировать этот scope. ### Создание версии из Chat Completions Endpoint принимает обычное тело Chat Completions. `messages` и `stream` не сохраняются. Первая системная инструкция переносится в отдельное поле версии; остальные сообщения отбрасываются. ```bash curl -X POST https://api.paipe.ru/v1/presets/support-agent/chat/completions \ -H "Authorization: Bearer $PAIPE_PRESET_WRITE_KEY" \ -H "Content-Type: application/json" \ -H "X-Preset-Name: Support agent" \ -H "X-Preset-Reason: Approved production configuration" \ -d '{ "model": "paipe/text-pro", "messages": [ {"role":"system","content":"Answer briefly and safely"}, {"role":"user","content":"This transient message is not stored"} ], "temperature": 0.2, "max_completion_tokens": 512 }' ``` Повторный вызов с тем же slug создаёт следующую версию. `X-Preset-Reason` обязателен и сохраняется как аудит-причина. `X-Preset-Name` и `X-Preset-Description` необязательны; если они отсутствуют при создании новой версии существующего пресета, текущие метаданные сохраняются. Для Responses используется `POST /v1/presets/{slug}/responses`. Поле `input` не сохраняется, а `instructions` становится системной инструкцией версии. ### Использование Поддерживаются три формы ссылки: ```json {"model":"@preset/support-agent","messages":[{"role":"user","content":"Hello"}]} ``` ```json {"preset":"support-agent","messages":[{"role":"user","content":"Hello"}]} ``` ```json { "model":"paipe/text-fast@preset/support-agent", "messages":[{"role":"user","content":"Hello"}] } ``` Поля запроса поверхностно переопределяют конфигурацию пресета. Собственная системная инструкция запроса заменяет системную инструкцию пресета. Если одновременно переданы несовпадающие ссылки через `model` и `preset`, запрос отклоняется до резервирования средств и обращения к модели. Для выполнения нужен только `inference:create`: runtime-ключу не требуется доступ к чтению системной инструкции или истории версий. ### Prompt caching `cache_control` можно сохранить в конфигурации Chat Completions или Responses, если выбранная модель объявляет эту возможность. Поле `session_id` всегда остаётся transient: оно не входит в версию пресета и должно передаваться при каждом runtime-вызове в JSON body или заголовке `X-Session-Id`. Для организации с обязательным ZDR создание версии с явным `cache_control` отклоняется до записи в базу. Подробный контракт, допустимые TTL и правила стабильной маршрутизации описаны в [руководстве по prompt caching](https://paipe.ru/docs/ai/prompt-caching.md). ### История, rollback и архив - `GET /v1/presets` — активные пресеты организации; - `GET /v1/presets/{slug}` — карточка и история версий от новой к старой; - `POST /v1/presets/{slug}/versions/{version}/designate` — назначить ранее созданную неизменяемую версию; - `DELETE /v1/presets/{slug}` — идемпотентно архивировать пресет. Архивированный пресет немедленно перестаёт приниматься новыми inference- запросами. История и ссылки уже выполненных запросов сохраняются. ### Безопасность данных Системная инструкция хранится в базе как часть конфигурации. Не помещайте туда API-ключи, пароли, персональные данные или сведения, запрещённые политикой организации. Тела пользовательских запросов при capture не сохраняются. --- ## Кеширование запросов Источник: https://paipe.ru/docs/ai/prompt-caching.md Paipe поддерживает provider-neutral prompt caching для `POST /v1/chat/completions` и `POST /v1/responses`. Механизм состоит из двух независимых частей: - `cache_control` явно запрашивает краткоживущий кэш промпта у совместимой модели; - `session_id` закрепляет последовательные запросы за тем же доступным внутренним маршрутом, повышая вероятность cache hit. Это не кэш готовых ответов. Paipe не сохраняет prompt/output content и не возвращает завершённый ответ повторно. Повтор `Idempotency-Key` по-прежнему подчиняется обычному idempotency-контракту. ### Явный prompt cache Модель должна объявлять `cache_control` или `prompt_caching` в `supported_parameters` ответа `GET /v1/models`. ```json { "model": "paipe/text-pro", "messages": [{"role": "user", "content": "Продолжи анализ документа"}], "cache_control": { "type": "ephemeral", "ttl": "1h" } } ``` Поддерживаются только: - `type: "ephemeral"`; - `ttl: "5m"` или `ttl: "1h"`; поле можно опустить для provider default. Неизвестные поля и другое время жизни отклоняются до резервирования средств. Если организация требует ZDR, явный `cache_control` также отклоняется до обращения к модели. Автоматическое кэширование конкретного маршрута регулируется его проверенным ZDR/commercial-permission профилем. ### Session stickiness Передайте стабильный идентификатор workflow одним из способов: ```http X-Session-Id: agent-workflow-2026-00042 ``` или: ```json { "session_id": "agent-workflow-2026-00042" } ``` Значение из JSON body имеет приоритет над заголовком. Допустимо от 1 до 256 UTF-8 символов. Не помещайте в идентификатор ФИО, телефон, email, текст запроса или другую персональную/секретную информацию — используйте случайный внутренний ID вашей системы. Paipe: 1. вычисляет HMAC-SHA-256 от `session_id` и сразу отбрасывает исходное значение; 2. ограничивает binding организацией, API-ключом, публичной моделью и типом API; 3. после успешного вызова сохраняет только HMAC, ссылку на маршрут и срок жизни; 4. при следующем вызове сначала пробует тот же активный и policy-compatible маршрут; 5. при истёкшем, отключённом или ZDR-несовместимом binding возвращается к обычному приоритету маршрутов. Маршрут не переключается после неоднозначной ошибки уже отправленного запроса: это предотвращает двойной upstream-вызов и двойное списание. Fallback разрешён только при достоверной ошибке до dispatch, например открытом circuit breaker. Binding по умолчанию действует один час. Оператор может задать от 60 до 86400 секунд через `ROUTING_SESSION_TTL_SECONDS`; истёкшие записи удаляются плановым worker. Ротация API-ключа намеренно создаёт новый изолированный набор binding. ### Responses API Тот же контракт работает для Responses: ```bash curl https://api.paipe.ru/v1/responses \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: workflow-step-00042" \ -H "X-Session-Id: agent-workflow-2026-00042" \ -d '{ "model": "paipe/text-pro", "input": "Продолжи предыдущий анализ", "cache_control": {"type":"ephemeral","ttl":"1h"}, "max_output_tokens": 512 }' ``` ### Пресеты и приоритет параметров `cache_control` можно сохранить в версионируемом AI-пресете. Request-level значение поверхностно переопределяет значение пресета. `session_id` всегда считается transient и в версию пресета не попадает. ZDR-политика проверяется и при создании версии, и при runtime-вызове. Поэтому ZDR-организация не сможет сохранить пресет, который тайно включает явный cache. ### Биллинг До dispatch Paipe резервирует консервативную максимальную стоимость. После ответа `cached_input_tokens` и `cache_write_tokens` тарифицируются отдельно по неизменяемой версии опубликованного RUB price book. Неиспользованный резерв возвращается. Если upstream не предоставил проверяемый usage, запрос не завершается бесплатным и переводится в безопасную сверку. ### Ошибки - `400 invalid_request` — неправильный `session_id` или `cache_control`; - `400 unsupported_parameter` — модель не объявляет явный prompt caching; - `400 prompt_caching_conflicts_with_zdr` — политика организации запрещает явный cache; - `400 invalid_session_id` — несколько неоднозначных `X-Session-Id` headers. --- ## Веб-поиск Источник: https://paipe.ru/docs/ai/web-search.md `POST /v1/chat/completions` и `POST /v1/responses` поддерживают публичный provider-neutral инструмент `paipe:web_search`. Он выполняется на стороне платформы, поэтому клиенту не нужно самостоятельно вызывать поисковый API и передавать результат модели. Инструмент доступен только для моделей, у которых `GET /v1/models` возвращает одновременно `tools` и `web_search` в `supported_parameters`. Внутренний поисковый провайдер, маршрут и его идентификаторы не входят в публичный контракт. Перед вызовом также проверяйте `capabilities.server_tools.web_search`: это текущее операционное состояние глобального safety gate, тогда как `supported_parameters` описывает техническую возможность модели. ### Запрос Одинаковое определение инструмента используется в Chat Completions и Responses: ```json { "tools": [ { "type": "paipe:web_search", "parameters": { "max_results": 5, "max_uses": 2, "max_total_results": 10, "search_context_size": "medium", "max_characters": 8000, "allowed_domains": ["example.com", "*.example.org"] } } ] } ``` Полный запрос через `curl`: ```bash curl https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: web-search-2026-08-11-0001" \ -d '{ "model": "paipe/search-pro", "messages": [{"role": "user", "content": "Что изменилось в последнем релизе?"}], "tools": [{ "type": "paipe:web_search", "parameters": {"max_results": 5, "max_uses": 2} }], "max_completion_tokens": 500 }' ``` С OpenAI-совместимым Python-клиентом передайте нестандартное определение через `extra_body`, чтобы сохранить строгую типизацию SDK: ```python from openai import OpenAI client = OpenAI(api_key="", base_url="https://api.paipe.ru/v1") response = client.chat.completions.create( model="paipe/search-pro", messages=[{"role": "user", "content": "Что изменилось в последнем релизе?"}], max_completion_tokens=500, extra_body={ "tools": [{ "type": "paipe:web_search", "parameters": {"max_results": 5, "max_uses": 2}, }] }, ) ``` Поля `parameters`: - `max_results`: 1–10 результатов на один поисковый запрос, по умолчанию 5; - `max_uses`: 1–5 оплачиваемых поисковых запросов, по умолчанию 1; - `max_total_results`: 1–50 и не больше `max_results * max_uses`; - `search_context_size`: `low`, `medium` или `high`; - `max_characters`: 1–30 000 символов поискового контекста; - `allowed_domains` или `excluded_domains`: 1–20 DNS-имён, допускается префикс `*.`. `allowed_domains` и `excluded_domains` взаимно исключают друг друга. В фильтрах принимаются именно домены, а не URL, пути или строки с query-параметрами. В одном запросе разрешено не более одного `paipe:web_search`. ### Биллинг В `GET /v1/models` поле `pricing.web_search` содержит цену одного поиска в рублях. Перед отправкой запроса платформа резервирует стоимость `max_uses`, а после ответа списывает только фактическое значение `usage.server_tool_use.web_search_requests`. Неиспользованная часть резерва освобождается. Цена и счётчики фиксируются в неизменяемом снимке тарифа и участвуют в сверке счёта поставщика. Пример usage: ```json { "usage": { "prompt_tokens": 420, "completion_tokens": 85, "total_tokens": 505, "server_tool_use": { "web_search_requests": 2 } } } ``` Если поставщик не вернул корректный счётчик, успешный запрос не списывается приблизительно: он переводится в безопасный контур сверки согласно общей политике settlement. ### Цитаты и безопасность Chat Completions возвращает проверенные `message.annotations` типа `url_citation` с URL, заголовком, фрагментом и индексами. Responses возвращает эквивалентные аннотации внутри `output[].content[].annotations`. Неизвестные внутренние поля удаляются. Поисковая фраза и полученный веб-контент обрабатываются внешней AI-инфраструктурой. Не передавайте персональные данные, коммерческую тайну или регулируемые сведения без утверждённого сценария обработки и трансграничной передачи. pAIpe не сохраняет поисковую фразу, страницы или ответ модели; в российской БД остаются только счётчик, модель, идентификаторы операции и финансовые данные. Основные ошибки: - `400 unsupported_model_capability` — модель не объявляет `tools` и `web_search`; - `400 invalid_request` — нарушены лимиты или схема параметров; - `422 web_search_price_not_configured` — для модели не опубликована цена поиска; - `503 server_tool_unavailable` — поиск временно отключён safety gate; повторяйте не раньше значения `Retry-After`; - `400 unpriced_provider_extension` — передан неизвестный server-managed инструмент. Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Чтение веб-страниц Источник: https://paipe.ru/docs/ai/web-fetch.md `POST /v1/chat/completions` и `POST /v1/responses` поддерживают provider-neutral инструмент `paipe:web_fetch`. Модель может прочитать страницу или PDF по URL и использовать извлечённый текст при формировании ответа. Клиент не вызывает отдельный scraper API и не передаёт скачанный документ в pAIpe. Инструмент доступен для моделей с `tools` в `supported_parameters`. Внутренний движок и инфраструктурный маршрут не входят в публичный контракт. Перед вызовом проверяйте `capabilities.server_tools.web_fetch` из `GET /v1/models`: значение учитывает текущий глобальный safety gate и может измениться после контролируемого аварийного отключения. ### Запрос Для каждого запроса обязателен доменный allowlist: ```json { "tools": [ { "type": "paipe:web_fetch", "parameters": { "max_uses": 2, "max_content_tokens": 4096, "allowed_domains": ["docs.example.ru", "*.support.example.ru"] } } ] } ``` Полный пример Chat Completions: ```bash curl https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: web-fetch-2026-08-11-0001" \ -d '{ "model": "paipe/text-pro", "messages": [{ "role": "user", "content": "Кратко изложи https://docs.example.ru/release-notes" }], "tools": [{ "type": "paipe:web_fetch", "parameters": { "max_uses": 1, "max_content_tokens": 4096, "allowed_domains": ["docs.example.ru"] } }], "max_completion_tokens": 500 }' ``` В Responses используется то же определение: ```json { "model": "paipe/text-pro", "input": "Суммируй https://docs.example.ru/release-notes", "tools": [{ "type": "paipe:web_fetch", "parameters": { "allowed_domains": ["docs.example.ru"] } }] } ``` Поля `parameters`: - `allowed_domains` — обязательные 1–20 DNS-имён; допускается префикс `*.`; - `max_uses` — 1–3 чтения в одном inference-запросе, по умолчанию 1; - `max_content_tokens` — 1–16 384 извлечённых токенов на одно чтение, по умолчанию 4096. URL, IP-адреса, `localhost`, пути, query-параметры и схемы протокола в `allowed_domains` не принимаются. Поля `engine`, `blocked_domains` и любые provider-specific настройки запрещены. В `tools` разрешён не более чем один `paipe:web_fetch`. ### Биллинг и резервирование Платформа принудительно использует direct-fetch режим без отдельной upstream платы. Поэтому `paipe:web_fetch` не создаёт скрытую цену за вызов: клиент платит только по опубликованным RUB-тарифам за фактические input/output-токены модели. До отправки запроса к обычной оценке входа добавляется консервативный резерв `max_uses * max_content_tokens`. Если вместе с запрошенным выводом он не помещается в context window модели, запрос отклоняется до финансового резерва с `400 context_length_exceeded`. После ответа списание выполняется по фактическому token usage, а не по максимальному резерву. Платные fetch-движки намеренно недоступны: публичный upstream-контракт пока не гарантирует отдельный точный счётчик фактических fetch-вызовов. Если upstream изменит цену direct-fetch режима, функция должна быть остановлена до появления версионированного RUB-тарифа, точного usage и сверки счёта поставщика. ### Безопасность данных Allowlist ограничивает допустимые домены, но не делает их содержимое доверенным. Страница может содержать prompt injection, ложные инструкции или ссылки на другие ресурсы. Передавайте только домены, которыми организация владеет либо которые явно одобрены её политикой данных; важные действия и ответы проверяйте на стороне приложения. Содержимое URL обрабатывается внешней AI-инфраструктурой и может участвовать в трансграничной передаче. Не помещайте в URL секреты, персональные данные, коммерческую тайну или регулируемые сведения без утверждённого основания и сценария обработки. pAIpe не скачивает страницу своим gateway и не сохраняет URL, извлечённый текст, prompt или ответ модели в PostgreSQL; сохраняются только контент-свободные метаданные запроса, token usage и RUB-списание. Основные ошибки: - `400 unsupported_model_capability` — модель не объявляет `tools`; - `400 invalid_request` — отсутствует allowlist, нарушен лимит или передано неизвестное поле; - `400 context_length_exceeded` — максимальный извлечённый контекст и вывод не помещаются в модель; - `503 server_tool_unavailable` — чтение URL временно выключено safety gate; используйте `Retry-After` и не делайте агрессивных повторов; - `400 unpriced_provider_extension` — передан непубличный server-managed тип. Полный машинно-читаемый контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Rerank Источник: https://paipe.ru/docs/ai/rerank.md `POST /v1/rerank` сортирует документы по релевантности запросу. Endpoint использует API-ключ со scope `inference:create`, опубликованные цены в рублях, лимиты организации, атомарный резерв и идемпотентное списание. Публичный контракт не раскрывает внутреннюю маршрутизацию и инфраструктурных провайдеров. ### Текстовый запрос ```bash curl https://api.paipe.ru/v1/rerank \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: rerank-2026-08-11-0001" \ -d '{ "model": "paipe/rerank-pro", "query": "Как подключить новую API-ноду?", "documents": [ "Добавьте stateless-ноду за балансировщик", "Удалите резервную копию базы", {"text": "Проверьте readiness и миграции перед вводом трафика"} ], "top_n": 2 }' ``` `query` — непустая строка. `documents` содержит от 1 до 256 непустых строк или объектов. `top_n` необязателен, должен быть положительным и не может превышать число документов; без него возвращаются все документы. Размер JSON ограничен 1 MiB. Модель должна объявлять `text` в `input_modalities` и `rerank` в `output_modalities`. ### Мультимодальные документы Объект документа может содержать `text`, `image` или оба поля: ```json { "model": "paipe/multimodal-rerank", "query": "Найди схему active-active кластера", "documents": [ {"text": "Схема основной площадки", "image": "https://cdn.example.ru/dc-a.png"}, {"image": "data:image/png;base64,iVBORw0KGgoAAA..."} ], "top_n": 1 } ``` Допускаются публичные HTTPS URL без credentials и fragment либо ограниченные data URL PNG, JPEG, WebP и GIF. Сервис не скачивает URL и не сохраняет содержимое. Для data URL действует лимит 700 000 декодированных байт; всего в запросе может быть до 16 изображений. Модель должна дополнительно объявлять `image` в `input_modalities`. Небезопасный URL, неизвестное поле или пустой объект отклоняются до резерва и обращения к модели. ### Ответ и биллинг ```json { "id": "rrk_7e622f55990f4a9189647ed6697ab086", "model": "paipe/rerank-pro", "results": [ {"document": "Добавьте stateless-ноду за балансировщик", "index": 0, "relevance_score": 0.97}, {"document": {"text": "Проверьте readiness и миграции перед вводом трафика"}, "index": 2, "relevance_score": 0.89} ], "usage": {"search_units": 1, "total_tokens": 42} } ``` Перед отправкой сервис консервативно резервирует стоимость каждой пары `query/document`. Для документа с изображением резервируется полный контекст модели, поскольку точная токенизация заранее неизвестна. После ответа сервис проверяет число результатов, диапазон и уникальность индексов, числовой score от 0 до 1, убывающую сортировку и неотрицательный `usage.total_tokens`. Затем атомарно списывается только фактическое число токенов по зафиксированной версии рублёвой цены, а остаток резерва освобождается. Возвращаемое поле `document` всегда восстанавливается из исходного запроса по проверенному индексу. Текст и metadata, присланные внешней моделью, не попадают в публичный ответ. Если ranking или usage нельзя безопасно проверить, запрос завершается `502 usage_unavailable`, а резерв освобождается без списания. ### Идемпотентность и повторы Передавайте уникальный `Idempotency-Key` для каждой логической операции. Повтор идентичного запроса возвращает тот же результат без второго вызова и списания. Повтор ключа с другим payload или другим inference endpoint вернёт `409 idempotency_conflict`. Успешный ответ содержит `Idempotency-Key` и `X-Request-ID`. Общий формат ошибок, статусы 400/402/404/409/429/502–504 и правила безопасного повтора описаны в [Chat Completions API](https://paipe.ru/docs/ai/chat-completions.md). Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Files API Источник: https://paipe.ru/docs/ai/files.md Files API позволяет один раз загрузить PDF до 100 MiB, а затем ссылаться на него в Chat Completions через provider-neutral `file_id`. Содержимое не возвращается клиенту после загрузки. ### Модель безопасности - `files:write` разрешает загрузку и физическое удаление; - `files:read` разрешает список и чтение только метаданных; - ключ организации видит только файлы без `project_id`; - проектный ключ видит только файлы своего проекта; - чужой, удалённый или истёкший `file_id` всегда выглядит как `404 file_not_found`; - до сохранения файл должен пройти ClamAV; при недоступном сканере загрузка отклоняется с `503`; - содержимое хранится в PostgreSQL независимыми блоками по 1 MiB, каждый блок защищён AES-256-GCM со случайным nonce и AAD, связывающим файл и номер блока; - имя, хеш и зашифрованные блоки неизменяемы на уровне БД; - после DELETE/expiry строки блоков и delivery grants удаляются hard delete, а в append-only журнале остаются только `file_id`, размер, tenant scope и действие. Hard delete немедленно убирает данные из доступного состояния приложения, но не означает синхронную перезапись каждого носителя: WAL, MVCC pages и резервные копии выводятся по утверждённому backup/retention schedule и проверяемой процедуре. Ключ `AI_FILE_ENCRYPTION_KEY_BASE64` должен быть одинаковым на всех активных нодах. При ротации новый ключ становится активным, а предыдущие временно перечисляются в `AI_FILE_PREVIOUS_ENCRYPTION_KEYS_BASE64`. Удалять старый ключ можно только после истечения или перешифрования всех файлов с соответствующим `storage_key_id`. ### Загрузка ```sh curl -X POST https://api.paipe.ru/v1/files \ -H "Authorization: Bearer $PAIPE_FILES_WRITE_KEY" \ -F "file=@agreement.pdf;type=application/pdf" \ -F "retention_hours=24" ``` ```json { "data": { "id": "file_qwertyuiopasdfghjklzxcvbn12", "object": "file", "filename": "agreement.pdf", "mime_type": "application/pdf", "size_bytes": 481920, "downloadable": false, "created_at": "2026-08-12T12:00:00Z", "expires_at": "2026-08-13T12:00:00Z", "scope": {"project_id": null} } } ``` `retention_hours` по умолчанию равен 24. Production-предел задаётся `AI_FILE_MAX_RETENTION_HOURS` и не может превышать 8760 часов. Рекомендуется выбирать минимальный срок, достаточный для бизнес-процесса. ### Список, метаданные и удаление ```sh curl "https://api.paipe.ru/v1/files?limit=100" \ -H "Authorization: Bearer $PAIPE_FILES_READ_KEY" curl "https://api.paipe.ru/v1/files/$FILE_ID" \ -H "Authorization: Bearer $PAIPE_FILES_READ_KEY" curl -X DELETE "https://api.paipe.ru/v1/files/$FILE_ID" \ -H "Authorization: Bearer $PAIPE_FILES_WRITE_KEY" ``` Пагинация использует непрозрачный подписанный `cursor`, действующий 24 часа. Не разбирайте и не сохраняйте его как бизнес-идентификатор. ### Использование в Chat Completions ```json { "model": "paipe/document-pro", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Составь таблицу обязательств сторон"}, {"type": "file", "file": {"file_id": "file_qwertyuiopasdfghjklzxcvbn12"}} ] } ] } ``` Для внешней модели gateway создаёт короткоживущий случайный capability URL. В БД хранится только SHA-256 токена; URL действует не более 15 минут и допускает ограниченное число чтений. `file_id` входит в идемпотентный request hash, а случайный delivery URL — нет. ### 152-ФЗ и трансграничная передача Зашифрованное хранение внутри российского PostgreSQL-контура не отменяет того, что при inference документ передаётся выбранной внешней модели. До загрузки персональных данных оператор обязан определить цель, правовое основание, сроки, категории данных, трансграничный маршрут, договорные меры и процедуру удаления. Files API является технической мерой и не заменяет юридическую оценку. Не помещайте имя файла, capability URL или содержимое в application logs, метрики, trace attributes и тикеты поддержки. Для расследования используйте content-free lifecycle evidence и публичный `file_id`. --- ## Изображения во входных данных Источник: https://paipe.ru/docs/ai/multimodal-images.md API принимает текст и изображения в `POST /v1/chat/completions`, `POST /v1/responses` и `POST /v1/embeddings`. Выбирайте модель, у которой `GET /v1/models` возвращает `"image"` в `input_modalities`; иначе запрос завершится кодом `unsupported_model_capability` до резервирования и обращения к модели. ### Chat Completions В пользовательском сообщении `content` может быть массивом текстовых и графических частей: ```json { "model": "paipe/vision-pro", "messages": [{ "role": "user", "content": [ {"type": "text", "text": "Что изображено на фотографии?"}, { "type": "image_url", "image_url": { "url": "https://cdn.example.ru/photo.webp", "detail": "low" } } ] }], "max_completion_tokens": 256 } ``` ### Responses Для Responses используйте часть `input_image`: ```json { "model": "paipe/vision-pro", "input": [{ "type": "message", "role": "user", "content": [ {"type": "input_text", "text": "Извлеки номер документа"}, { "type": "input_image", "image_url": "https://cdn.example.ru/document.png", "detail": "auto" } ] }], "max_output_tokens": 256 } ``` ### Embeddings Для мультимодального embedding передайте массив объектов с `content`. Один объект создаёт один совместный вектор для всех его частей: ```json { "model": "paipe/multimodal-embedding", "input": [{ "content": [ {"type": "text", "text": "Эталон"}, { "type": "image_url", "image_url": {"url": "https://cdn.example.ru/reference.png"} } ] }] } ``` ### Источники и ограничения - публичный HTTPS URL без credentials и fragment либо base64 data URL; - PNG, JPEG, WebP и GIF; - `detail`: `auto`, `low` или `high`; - до 16 изображений, 64 частей в одном сообщении и 256 частей в запросе; - URL не длиннее 8192 байт; - декодированное data URL изображение не больше 700 000 байт; - полный JSON-запрос не больше 1 MiB. Gateway не загружает URL сам: он проверяет форму адреса и передаёт его выбранной модели. Прямые localhost, `.local`, loopback, private, link-local и reserved IP literals отклоняются. Клиент отвечает за доступность HTTPS URL для внешней модели и за срок жизни подписанной ссылки. ### Биллинг Размер удалённого изображения и его фактическая токенизация заранее неизвестны. Поэтому при наличии изображения сервис консервативно резервирует максимально возможную стоимость входного контекста с учётом `max_completion_tokens` или `max_output_tokens`. После ответа резерв заменяется точным списанием по фактическому usage, а остаток сразу возвращается на баланс. ### Конфиденциальность Тексты, data URL и адреса изображений не сохраняются в записи inference- запроса и не добавляются в прикладные логи. Хранятся только digest запроса, usage, финансовые ссылки и технические статусы. Изображение всё равно передаётся внешней модели: до отправки персональных данных убедитесь, что это разрешено договором, поручением на обработку, политикой организации и утверждённым сценарием трансграничной передачи. Не помещайте секреты в query string URL. Для чувствительных файлов используйте короткоживущую подписанную HTTPS-ссылку с минимальными правами либо data URL в пределах лимита запроса. ### Ошибки Публичный API использует безопасные коды без текста ответа поставщика: - `invalid_image_url` — URL или data URL не соответствует контракту; - `invalid_image` — повреждённые данные или неподдерживаемый `detail`; - `image_too_large` — превышен лимит data URL; - `unsupported_image_format` — формат не PNG/JPEG/WebP/GIF; - `too_many_images` — больше 16 изображений; - `unsupported_model_capability` — модель не принимает изображения; - `image_not_found` и `image_download_failed` — модель не смогла получить URL; - `content_policy_violation` — изображение отклонено политикой безопасности. Полная схема находится в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). Для PDF-документов используйте отдельный native-file контракт из [pdf-inputs.md](https://paipe.ru/docs/ai/pdf-inputs.md). Для аудио используйте raw-base64 контракт из [audio-inputs.md](https://paipe.ru/docs/ai/audio-inputs.md). --- ## PDF во входных данных Источник: https://paipe.ru/docs/ai/pdf-inputs.md `POST /v1/chat/completions` принимает PDF как часть пользовательского сообщения. Выбирайте модель, у которой `GET /v1/models` возвращает `"file"` в `input_modalities`: ```bash curl "https://api.paipe.ru/v1/models?input_modalities=file" \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Эта страница описывает transient HTTPS/base64 inputs. Для повторного использования документа до 100 MiB применяйте зашифрованный [`Files API`](https://paipe.ru/docs/ai/files.md) и передавайте `{"file_id":"file_…"}`. Поддерживаются только модели с нативным вводом файлов. Платформа принудительно выбирает native PDF processing и не принимает клиентское поле `plugins`. Это исключает неучтённую стоимость внешнего OCR/parser и сохраняет публичный тариф в рублях за миллион токенов. ### PDF по HTTPS URL ```bash curl https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: contract-summary-2026-08-11" \ -d '{ "model": "paipe/document-pro", "messages": [{ "role": "user", "content": [ {"type": "text", "text": "Кратко перечисли обязательства сторон"}, { "type": "file", "file": { "filename": "agreement.pdf", "file_data": "https://cdn.example.ru/agreement.pdf" } } ] }], "max_completion_tokens": 512 }' ``` URL должен использовать HTTPS, не содержать credentials или fragment и быть не длиннее 8192 байт. Прямые localhost, `.local`, loopback, private, link-local и reserved IP literals отклоняются. Gateway не загружает URL самостоятельно — файл получает выбранная внешняя модель. ### PDF как base64 data URL Для небольшого локального документа передайте: ```json { "type": "file", "file": { "filename": "акт.pdf", "file_data": "data:application/pdf;base64,JVBERi0xLjQK..." } } ``` Декодированный PDF ограничен 700 000 байт, а весь JSON-запрос — 1 MiB. Сервис проверяет MIME envelope, заголовок `%PDF-`, завершающий маркер `%%EOF` и безопасное имя файла длиной до 255 байт. Это bounded envelope validation, а не антивирусная или экспертная проверка содержимого документа. Один запрос может содержать до 8 PDF, до 64 content parts в сообщении и до 256 parts суммарно. PDF разрешён только в сообщении `user`. ### Биллинг Точное число входных токенов PDF до обработки неизвестно. Поэтому платформа резервирует максимально возможную стоимость входного контекста с учётом `max_completion_tokens`. После ответа резерв заменяется точным списанием по фактическому usage модели; неиспользованный остаток сразу освобождается. Нативная обработка оплачивается только как input tokens согласно опубликованной рублёвой цене модели. OCR для сканов и parser fallback намеренно не включены: для них потребуется отдельная измеримая единица тарификации, реестр субпроцессоров и юридически утверждённая политика обработки. ### Конфиденциальность Прямой PDF, его URL и имя не сохраняются в inference-записи и не попадают в прикладные логи. Хранятся только digest нормализованного запроса, usage, финансовые ссылки и технические статусы. Сам документ передаётся внешней модели, поэтому до отправки персональных данных должны быть утверждены договор, поручение на обработку, основание, категории данных, срок и сценарий трансграничной передачи. Не помещайте персональные данные или секреты в query string. Для чувствительных документов используйте короткоживущую подписанную HTTPS-ссылку с минимальными правами либо base64 в пределах лимита. ### Ошибки - `invalid_file_url` — небезопасный или неподдерживаемый адрес; - `invalid_file` — неверное имя, MIME envelope или структура PDF; - `file_too_large` — превышен лимит inline PDF; - `too_many_files` — больше 8 PDF; - `unsupported_model_capability` — модель не объявляет native `file` input; - `invalid_request` — в том числе попытка передать клиентское поле `plugins`. Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). Для аудиозаписей используйте отдельный контракт [audio-inputs.md](https://paipe.ru/docs/ai/audio-inputs.md). --- ## Аудио во входных данных Источник: https://paipe.ru/docs/ai/audio-inputs.md Для генерации речи см. отдельное руководство [«Аудиоответы Chat Completions»](https://paipe.ru/docs/ai/audio-outputs.md). `POST /v1/chat/completions` принимает аудиофрагменты в пользовательских сообщениях. Выбирайте модель, у которой `GET /v1/models` возвращает `"audio"` в `input_modalities`: ```bash curl "https://api.paipe.ru/v1/models?input_modalities=audio" \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Аудио передаётся только как raw base64. HTTPS URL и data URL не поддерживаются. Такой контракт соответствует возможностям моделей и не заставляет платформу загружать файлы по произвольным адресам. ### Запрос ```bash curl https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: audio-analysis-20260811-01" \ -d '{ "model": "paipe/audio-pro", "messages": [{ "role": "user", "content": [ {"type": "text", "text": "Сделай краткую расшифровку записи"}, { "type": "input_audio", "input_audio": { "data": "UklGRiQAAABXQVZFZm10IBAAAAABAAEA...", "format": "wav" } } ] }], "max_completion_tokens": 512 }' ``` `input_audio.data` содержит только стандартный base64 без префикса `data:audio/...`. Поле `format` обязательно и должно соответствовать реальному контейнеру или PCM-представлению. Поддерживаемые значения: - `wav`; - `mp3`; - `aiff`; - `aac`; - `ogg`; - `flac`; - `m4a`; - `pcm16`; - `pcm24`. Фактический набор форматов может быть уже у конкретной модели. Перед production- интеграцией проверьте документацию выбранной модели и тестовый запрос без персональных данных. ### Ограничения - до 8 аудиофрагментов в запросе; - до 700 000 декодированных байт на один фрагмент; - до 64 content parts в одном сообщении и до 256 во всём запросе; - весь JSON-запрос ограничен 1 MiB; - аудио разрешено только в сообщениях с ролью `user`; - URL, data URL, нестандартный URL-safe base64 и неизвестные поля отклоняются; - контейнерные форматы проходят bounded signature validation. Проверка сигнатуры защищает контракт от очевидного несоответствия формата, но не является антивирусной, медиаэкспертизой или гарантией корректности всех внутренних блоков файла. ### Биллинг Каталог публикует отдельную цену `pricing.audio_input` в рублях за миллион входных аудиотокенов. Обычные текстовые input tokens и audio input tokens считаются по разным ставкам. До выполнения точное число аудиотокенов неизвестно. Платформа резервирует максимально возможную стоимость оставшегося контекста по самой дорогой входной ставке модели. После ответа резерв заменяется точным списанием: - `prompt_tokens_details.audio_tokens` → `audio_input_tokens`; - остальные незакэшированные prompt tokens → `input_tokens`; - неиспользованный резерв освобождается. Если для audio-capable модели не опубликована отдельная положительная ставка, запрос отклоняется до резервирования и обращения к внешней модели с кодом `audio_input_price_not_configured`. ### Конфиденциальность Base64-аудио не сохраняется в inference-записи, финансовой истории или прикладных логах. Хранятся только digest нормализованного запроса, token usage, финансовые ссылки и технические статусы. Само аудио передаётся выбранной внешней модели. Перед передачей записей с голосом или другими персональными данными должны быть утверждены правовое основание, договор обработки, перечень разрешённых моделей, политика трансграничной передачи и срок хранения у обработчика. Для особо чувствительных разговоров используйте обезличивание и отдельный организационный allowlist. ### Ошибки - `invalid_audio` — base64 или сигнатура не соответствует формату; - `unsupported_audio_format` — формат отсутствует в allowlist; - `audio_too_large` — превышен лимит декодированного фрагмента; - `too_many_audio_files` — передано больше 8 фрагментов; - `unsupported_model_capability` — модель не объявляет audio input; - `audio_input_price_not_configured` — отсутствует отдельный RUB-тариф. Полный машинно-читаемый контракт находится в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Видео во входных данных Источник: https://paipe.ru/docs/ai/video-inputs.md `POST /v1/chat/completions` принимает видео в пользовательском сообщении через content part `video_url`. Выбирайте только модель, которая объявляет `video` в `input_modalities`: ```http GET /v1/models?input_modalities=video ``` ### Запрос по HTTPS URL ```json { "model": "paipe/video-pro", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Опиши ключевые события"}, { "type": "video_url", "video_url": {"url": "https://cdn.example.ru/demo.mp4"} } ] } ], "max_completion_tokens": 512 } ``` URL должен использовать HTTPS, не содержать credentials и fragment и не вести на localhost или приватный IP. Gateway не скачивает URL самостоятельно: источник передаётся выбранной модели. Поэтому поддержка отдельных хостингов и видеоплатформ зависит от модели и фактического маршрута. Используйте доступный без cookies URL с ограниченным сроком жизни. ### Inline base64 Для небольшого ролика передайте data URL: ```json { "type": "video_url", "video_url": { "url": "data:video/mp4;base64,AAAAGGZ0eXBpc29t..." } } ``` Разрешены MIME-типы `video/mp4`, `video/mpeg`, `video/mov` и `video/webm`. Gateway декодирует base64, проверяет сигнатуру контейнера и ограничивает каждую часть 700 000 байтами. В одном запросе допускается до 4 видео, до 64 content parts в сообщении и до 256 частей суммарно. Общий JSON body ограничен 1 MiB. Для более крупных файлов используйте публичный HTTPS URL. Видео разрешено только в сообщениях с ролью `user`. Лишние поля и модель без video capability отклоняются до отправки наружу. ### Биллинг До вызова модели резервируется стоимость всего доступного input-контекста: `context_length - max_completion_tokens`. После успешного ответа платформа списывает фактические input/output tokens по опубликованным RUB-ставкам модели, а остаток резерва освобождает. Внутренняя цена и диагностические данные внешнего провайдера клиенту не возвращаются. ### Приватность pAIpe не сохраняет тело запроса, видео или ответ модели: в журнале остаются hash, usage, сумма и технические идентификаторы. Видео при этом передаётся внешней модели, а URL может быть загружен ею напрямую. Для персональных данных заранее зафиксируйте правовое основание, поручение на обработку, допустимую географию, срок жизни ссылки и уведомление о трансграничной передаче. ZDR ограничивает retention у внешней стороны, но не отменяет сам факт передачи. ### Ошибки - `invalid_video_url` — небезопасный URL или неверная форма объекта; - `invalid_video` — base64 или сигнатура контейнера не прошли проверку; - `unsupported_video_format` — формат не входит в allowlist; - `video_too_large` — inline-файл превышает лимит; - `too_many_videos` — в запросе больше четырёх видео; - `unsupported_model_capability` — модель не объявляет video input. Известные диагностические типы внешней модели нормализуются в безопасные коды; оригинальный текст и metadata наружу не передаются. --- ## Генерация изображений Источник: https://paipe.ru/docs/ai/image-generation.md `POST /v1/images` генерирует от одного до десяти изображений и возвращает их как base64. Маршрут использует обычный Bearer API-ключ со scope `inference:create`, tenant-политику, ZDR-маршрутизацию, лимиты и заголовок `Idempotency-Key`. ### Минимальный запрос ```bash curl https://api.paipe.ru/v1/images \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: product-card-20260811-001" \ -d '{ "model": "paipe/image-pro", "prompt": "Фотография товара на нейтральном фоне", "n": 1, "output_format": "png" }' ``` Ответ содержит публичный id, публичный alias модели, полный массив `data`, безопасную token-статистику (если она была предоставлена) и `paipe.request_id`. Внутренний поставщик, маршрут и его стоимость не раскрываются. ```json { "id": "img_018f...", "created": 1786000000, "model": "paipe/image-pro", "data": [ {"b64_json": "iVBORw0KGgo...", "media_type": "image/png"} ], "usage": {"prompt_tokens": 24, "completion_tokens": 1024, "total_tokens": 1048}, "paipe": {"request_id": "018f0000-0000-7000-8000-000000000000"} } ``` ### Параметры - `prompt` — обязательная непустая строка до 65 536 байт; - `n` — 1–10, по умолчанию 1; - `quality`, `resolution` или совместимый alias `size` выбирают опубликованное тарифное правило; одновременно передавать `resolution` и `size` нельзя; - `aspect_ratio` принимает отношение `width:height` либо `auto`; `output_format`, `background`, `output_compression`, `seed` принимаются только если модель объявила соответствующую capability; - `output_format` ограничен `png`, `jpeg`, `webp`; SVG не принимается; - `stream: true` включает SSE только если модель публикует одновременно `verified: true` и `streaming: true`; для legacy/unverified capability запрос отклоняется до резервирования. Неизвестные поля отклоняются до резервирования средств. ### Model capability discovery Call `GET /v1/models?output_modalities=image` before constructing an Image API request. Each returned model has a provider-neutral `capabilities.image_generation` object: ```json { "available": true, "verified": true, "streaming": true, "parameters": { "n": {"type": "range", "min": 1, "max": 4}, "resolution": {"type": "enum", "values": ["1K", "2K"]}, "output_format": {"type": "enum", "values": ["png", "jpeg", "webp"]} } } ``` `verified: true` means the limits came from a dedicated typed capability catalog and were frozen during model publication. The gateway enforces those limits before reserving funds. `available: false` means the model cannot be used through `/v1/images`. A legacy `verified: false` projection is conservative and should not be used to assume support for optional parameters. `streaming: true` means Paipe has verified the dedicated upstream contract and can safely settle this model's image stream. Never infer streaming support from the model name or a legacy `verified: false` record. ### Streaming Use `curl -N` or an SSE client and keep the same idempotency key across a network retry: ```bash curl -N https://api.paipe.ru/v1/images \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: product-card-stream-20260811-001" \ -d '{ "model": "paipe/image-pro", "prompt": "Фотография товара на нейтральном фоне", "n": 1, "stream": true }' ``` Paipe передаёт bounded preview без внутренних данных поставщика: ```text data: {"id":"img_...","type":"image_generation.partial_image","model":"paipe/image-pro","partial_image_index":0,"b64_json":"...","paipe":{"request_id":"..."}} data: {"id":"img_...","type":"image_generation.completed","model":"paipe/image-pro","created":1786000000,"image_index":0,"b64_json":"...","media_type":"image/png","usage":{"prompt_tokens":24,"completion_tokens":1024,"total_tokens":1048},"paipe":{"request_id":"..."}} data: [DONE] ``` Полноразмерные `completed` события не проксируются напрямую: адаптер сначала собирает ровно `n` результатов, проверяет base64, сигнатуру, формат, размеры и фактический usage, затем атомарно списывает сумму и только после этого отдаёт результат. `usage` присутствует только в последнем `completed` событии. При provider error, повреждённом событии, превышении лимита или отсутствии `[DONE]` Paipe завершает SSE нормализованным `error` и `[DONE]`. Если preview уже мог быть доставлен, резерв остаётся активным, а запрос получает `reconciliation_required`; оператор сверяет его с provider statement. Клиенту нельзя автоматически повторять такой запрос с новым `Idempotency-Key`. ### Image-to-image До 16 референсов передаются в `input_references`. Разрешены только строго типизированные объекты с публичным HTTPS URL либо bounded data URL: ```json { "model": "paipe/image-pro", "prompt": "Сохранить композицию, заменить фон", "input_references": [ { "type": "image_url", "image_url": {"url": "https://cdn.example.org/reference.png"} } ] } ``` Локальные адреса, loopback/private IP, URL с credentials/fragment, лишние заголовки и неоднозначные структуры запрещены. Gateway не скачивает референс и не сохраняет prompt, изображение или ответ в базе. ### Биллинг и ошибки До обращения к поставщику сервер выбирает наиболее точное immutable правило: `quality+resolution`, затем одно совпадающее поле, затем `default`. Для каждого output заранее резервируется опубликованный верхний предел, а references резервируются поштучно. Списание возможно только когда ответ содержит ровно `n` валидных PNG/JPEG/WebP объектов. При ошибке, таймауте, частичном, повреждённом или превышающем резерв buffered-ответе весь резерв освобождается. Для прерванного streaming-ответа после возможной доставки preview действует консервативная сверка с активным резервом, описанная выше. Output runtime поддерживает три единицы: - `image` — точное количество успешно проверенных изображений; - `megapixel` — сумма пикселей из заголовков PNG/JPEG/WebP, где один пиксель равен одной миллионной мегапикселя; - `token` — фактические output tokens из нормализованного provider usage. Для `megapixel` и `token` правило обязательно содержит `reservation_limit_per_item`; фактическое списание округляется вверх только до одного nanorub и не может превысить резерв. Если token usage отсутствует, запрос не списывается. Внешние reference URL gateway намеренно не скачивает, поэтому `input_reference` поддерживает только `unit: image`. Отсутствующий тариф или legacy-правило без лимита возвращает безопасную `422` billing error до upstream-вызова. Для финансовой сверки `GET /v1/generation?id=...` возвращает counts, `output_pixels` и точную десятичную строку `output_megapixels` в `images`. Provider-statement CSV содержит `image_output_count`, `image_reference_count` и `image_output_pixels`. Эти значения сверяются с immutable request usage и исходными USD-ставками правила внутри PostgreSQL guard. --- ## Стоимость изображений Источник: https://paipe.ru/docs/ai/image-generation-pricing.md Модели с `image` в `output_modalities` публикуют массив `pricing.image_generation` в ответах `GET /v1/models` и `GET /v1/model?id=...`. Каждый элемент — неизменяемое правило опубликованной версии прайс-листа: ```json { "dimension": "output_image", "unit": "image", "billing_scale": "per_unit", "selector": "quality=high;resolution=2k", "quality": "high", "resolution": "2k", "reservation_limit_per_item": "1", "price": "9.6" } ``` - `dimension` — `output_image`, `input_image` или `input_reference`; - `unit` — `image`, `megapixel` или `token`; - `billing_scale` — `per_unit` для image/megapixel и `per_million` для token; - `selector` — каноническая комбинация `quality`/`resolution` либо `default`; - `reservation_limit_per_item` — верхний предел резерва на один output: изображения, мегапиксели или output tokens в зависимости от `unit`; - `price` — точная десятичная строка в рублях без float-округления. Клиент выбирает самое точное правило, совпадающее с параметрами запроса, затем правило с одним совпадающим selector и только после него `default`. Одинаковые selectors в одной dimension запрещены. Исходная USD-ставка, наценка и внутренний маршрут поставщика в публичный контракт не входят. ### Финансовый gate Прайс-лист с image-output моделью невозможно опубликовать без default `output_image` правила (без quality/resolution). RUB-цена рассчитывается сервером из неизменяемого FX snapshot, исходной ставки, наценки и налога; создатель прайса не может сам его утвердить. После публикации PostgreSQL запрещает изменение и удаление правил. Публичный `POST /v1/images` поддерживает output-правила `image`, `megapixel` и `token`. До отправки запроса резервируется цена опубликованного верхнего предела для каждого output и поштучная цена input references. После полного и проверенного ответа списывается только фактическое количество изображений, пикселей или output tokens; приблизительное списание не допускается. Для внешних reference URL разрешено только `unit: image`, потому что gateway не скачивает эти ресурсы. Полный контракт описан в [Image API](https://paipe.ru/docs/ai/image-generation.md). --- ## Генерация видео Источник: https://paipe.ru/docs/ai/video-generation.md Video API использует схему submit → poll → download и не раскрывает поставщика, его job ID или временную ссылку. Все запросы требуют серверный API-ключ со scope `inference:create`. Передавайте собственный `Idempotency-Key` длиной 8–128 символов: безопасный повтор возвращает тот же локальный job и не создаёт второе списание. ### 1. Получить доступные модели и цены ```bash curl https://api.paipe.ru/v1/videos/models \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Эндпоинт возвращает только модели с проверенными video capabilities и опубликованной ценой в рублях за секунду. Варианты цены различаются по `resolution` и `generate_audio`; исходная цена и внутренний поставщик отсутствуют. ### 2. Отправить задачу ```bash curl https://api.paipe.ru/v1/videos \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: campaign-video-20260811-01" \ -d '{ "model": "paipe/video-pro", "prompt": "Медленный пролёт над лесным озером на рассвете", "duration": 5, "resolution": "720p", "generate_audio": false, "user": "internal-customer-42" }' ``` `duration` обязателен, если каталог модели явно не содержит проверенное значение по умолчанию. Это исключает неоднозначный финансовый резерв. Допустимые `duration`, `resolution`, `aspect_ratio`, `size`, `seed`, `generate_audio` и референсы берутся из `/v1/videos/models`; неизвестные поля отклоняются. Нельзя одновременно передавать `size` с `resolution`/`aspect_ratio`, а также `frame_images` с `input_references`. Референс имеет форму: ```json { "type": "image_url", "image_url": {"url": "https://cdn.example.ru/reference.webp"} } ``` Для `frame_images` дополнительно требуется `frame_type`: `first_frame` или `last_frame`. Разрешены публичные HTTPS URL и ограниченные data URL PNG, JPEG, GIF или WebP. Подписанная ссылка должна жить достаточно долго для внешней обработки. Успешная постановка возвращает `202 Accepted`: ```json { "id": "765d5080-18c6-4938-b27b-b736beb2e6b0", "object": "video.generation.job", "model": "paipe/video-pro", "status": "pending", "duration": 5, "resolution": "720p", "aspect_ratio": null, "size": null, "generate_audio": false, "created_at": 1786464000, "expires_at": 1786550400, "request_id": "d9aa81a6-0de2-4601-a04e-323595239afe", "content": [] } ``` ### 3. Проверять статус ```bash curl https://api.paipe.ru/v1/videos/$VIDEO_JOB_ID \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` Возможны `pending`, `in_progress`, `completed`, `failed`, `cancelled`, `expired` и `reconciliation_required`. Используйте backoff с jitter, начиная примерно с 5–10 секунд; не создавайте новый POST для polling. После `completed` появляется массив локальных ссылок: ```json "content": [{"index": 0, "url": "/v1/videos/765d5080-18c6-4938-b27b-b736beb2e6b0/content?index=0"}] ``` ### 4. Скачать результат ```bash curl -L "https://api.paipe.ru/v1/videos/$VIDEO_JOB_ID/content?index=0" \ -H "Authorization: Bearer $PAIPE_API_KEY" \ --output result.mp4 ``` Содержимое доступно только после атомарного RUB-списания, проксируется без раскрытия upstream URL, не кэшируется шлюзом и ограничено 1 GiB. Скачайте его до `expires_at`; это окно доступности, а не обещание долговременного хранения. ### Биллинг и безопасные отказы Сумма резерва равна `duration × опубликованная цена варианта`. Ставка и длительность фиксируются в неизменяемом evidence до внешнего вызова. При успешной генерации резерв атомарно списывается до публикации ссылки. Явный provider failure освобождает резерв. Неоднозначный сетевой исход или исчерпание polling оставляет резерв активным и переводит запрос в четырёхглазую сверку — автоматическое повторное списание не выполняется. Video API намеренно недоступен организациям с обязательным ZDR. Проверка идёт до резерва и внешнего вызова. pAIpe не сохраняет prompt, референсы или видео, но они передаются внешней модели, а поставщик может временно хранить результат. До отправки персональных или конфиденциальных данных заказчик должен иметь утверждённый договорный и трансграничный сценарий. Точный машинный контракт и нормализованные ошибки находятся в [`openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Распознавание речи Источник: https://paipe.ru/docs/ai/transcriptions.md `POST /v1/audio/transcriptions` преобразует аудиозапись в текст. Endpoint использует API-ключ со scope `inference:create`, опубликованные цены в рублях, лимиты организации, атомарный резерв и идемпотентное списание. Публичный ответ не раскрывает внутреннюю маршрутизацию и инфраструктурного поставщика. ### Запрос ```bash curl https://api.paipe.ru/v1/audio/transcriptions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: transcription-2026-08-11-0001" \ -d '{ "model": "paipe/transcribe-pro", "input_audio": { "data": "UklGRiQAAABXQVZFZm10IBAAAAABAAEA...", "format": "wav" }, "language": "ru", "temperature": 0 }' ``` `input_audio.data` содержит стандартный base64 без префикса `data:`. URL и data URL не принимаются. Допустимы WAV, MP3, AIFF, AAC, OGG, FLAC, M4A, PCM16 и PCM24. После декодирования файл ограничен 700 000 байт, весь JSON — 1 MiB. Gateway проверяет base64, формат и сигнатуру контейнера до резервирования и обращения к модели. Выбранная модель должна объявлять `audio` в `input_modalities` и `transcription` в `output_modalities`. Необязательные `language` и `temperature` разрешены только когда модель публикует соответствующий `supported_parameter`. `language` задаётся двухбуквенным lowercase кодом ISO-639-1, `temperature` — числом от 0 до 1. Если язык неизвестен, не передавайте `language`: модель выполнит автоматическое определение. ### Ответ ```json { "id": "trn_2a0fe23ce4834ab19f6a16aa35089047", "model": "paipe/transcribe-pro", "text": "Добрый день, начинаем совещание.", "usage": { "input_tokens": 83, "output_tokens": 30, "total_tokens": 113, "seconds": 9.2 }, "paipe": { "request_id": "2a0fe23c-e483-4ab1-9f6a-16aa35089047" } } ``` Gateway принимает ответ только если транскрипт является непустым валидным UTF-8 текстом, token usage неотрицателен и `total_tokens = input_tokens + output_tokens`. `seconds` необязателен и должен быть неотрицательным. Внешние `provider`, `cost`, идентификаторы и metadata удаляются. ### Резервирование и списание До отправки аудио сервис резервирует консервативный верхний предел полного контекста для audio input и text output: заранее достоверно определить токенизацию и длину транскрипта невозможно. После проверенного ответа: - `usage.input_tokens` списывается по `pricing.audio_input`; - `usage.output_tokens` списывается по обычной output-ставке; - неиспользованная часть резерва освобождается атомарно. Если usage отсутствует, противоречив или превышает резерв, транскрипт не возвращается клиенту, списание не выполняется, а запрос завершается безопасной ошибкой. В истории сохраняются только хеш запроса, числовой usage, сумма и технические идентификаторы — аудиобайты и текст транскрипта не сохраняются. ### Персональные данные Голос, содержание разговора и транскрипт могут относиться к персональным данным. Перед использованием endpoint организация должна определить законное основание и цель обработки, уведомить участников, ограничить доступ и сроки хранения в своей системе. Аудио транзитно передаётся выбранной внешней модели; для организаций с обязательным ZDR маршрутизация остаётся fail-closed. ### Идемпотентность и повторы Передавайте уникальный `Idempotency-Key` для каждой логической операции. Повтор идентичного запроса не создаёт второе списание. Использование того же ключа с другим аудио или endpoint вернёт `409 idempotency_conflict`. Успешный ответ содержит `Idempotency-Key` и `X-Request-ID`. Общий формат ошибок, статусы 400/402/404/409/429/502–504 и правила безопасного повтора описаны в [Chat Completions API](https://paipe.ru/docs/ai/chat-completions.md). Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Синтез речи Источник: https://paipe.ru/docs/ai/text-to-speech.md `POST /v1/audio/speech` синтезирует речь из UTF-8 текста и возвращает бинарный MP3 или PCM-поток. Требуется API-ключ со scope `inference:create` и уникальный `Idempotency-Key` длиной 8–128 ASCII-символов. ```bash curl https://api.paipe.ru/v1/audio/speech \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: speech-order-00042" \ --data '{ "model": "paipe/speech-pro", "input": "Добро пожаловать в сервис", "voice": "neutral", "response_format": "mp3", "speed": 1.0, "user": "customer-user-42" }' \ --output speech.mp3 ``` Допустимые форматы: `mp3` (`audio/mpeg`) и `pcm` (`audio/pcm`, 16-bit little-endian). По умолчанию используется `pcm`. Поле `input` ограничено 50 000 Unicode-символов; `speed` — диапазоном 0.25–4.0. `voice` и `speed` принимаются только когда выбранная модель объявляет соответствующие capability. Тарификация выполняется по опубликованной ставке `pricing.input_characters` в рублях за 1 млн Unicode-символов. Точная сумма резервируется до вызова и атомарно списывается перед выдачей аудио. Текст и аудио не сохраняются. Значение `user` заменяется tenant-bound HMAC-ссылкой и не передаётся внешней модели. Успешный бинарный ответ намеренно не сохраняется для replay. Повтор успешного запроса с тем же ключом возвращает `409 idempotency_replay_unavailable`; клиент не должен создавать новый ключ автоматически, пока не определит бизнес-исход первого запроса. Voice cloning и `input_references` не поддерживаются. --- ## Аудиоответы Источник: https://paipe.ru/docs/ai/audio-outputs.md `POST /v1/chat/completions` умеет возвращать синтезированную речь через SSE. Выбирайте модель, у которой `GET /v1/models` содержит `"audio"` одновременно в `output_modalities` и опубликованную ставку `pricing.audio_output`: ```bash curl "https://api.paipe.ru/v1/models?output_modalities=text,audio" \ -H "Authorization: Bearer $PAIPE_API_KEY" ``` ### Запрос Аудиоответ всегда требует `stream: true`, ровно две output-модальности — `text` и `audio` — и объект `audio` с голосом и форматом: ```bash curl -N https://api.paipe.ru/v1/chat/completions \ -H "Authorization: Bearer $PAIPE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: speech-demo-20260811-01" \ -d '{ "model": "paipe/audio-pro", "messages": [{"role": "user", "content": "Дружелюбно поздоровайся"}], "modalities": ["text", "audio"], "audio": {"voice": "alloy", "format": "wav"}, "stream": true, "max_completion_tokens": 512 }' ``` Допустимые форматы gateway: `wav`, `mp3`, `flac`, `opus`, `pcm16`. Конкретная модель может поддерживать меньше форматов и собственный набор голосов. Перед production-интеграцией проверьте неперсональный тестовый запрос выбранной модели. ### Сборка ответа Каждое SSE-событие содержит JSON в строке `data:`. Аудиофрагменты и синхронный текст находятся в `choices[].delta.audio`: ```json { "choices": [{ "index": 0, "delta": { "audio": { "data": "UklGRg...", "transcript": "Здравствуйте" } } }] } ``` Склеивайте `audio.data` в порядке получения, затем один раз декодируйте итоговую base64-строку. `audio.transcript` также склеивается по порядку. Не декодируйте произвольные JSON-поля и завершайте чтение только после `data: [DONE]`. Финальное событие перед `[DONE]` содержит `usage`. Gateway применяет backpressure: следующий upstream-чанк обрабатывается после передачи предыдущего клиенту. Одно незавершённое SSE-событие ограничено 1 MiB. При обрыве до достоверного финального usage резерв не освобождается автоматически, а запрос переводится в безопасную ручную сверку. ### Биллинг Каталог публикует `pricing.audio_output` в рублях за миллион выходных аудиотокенов. До запроса платформа резервирует максимальную стоимость output-токенов по самой дорогой применимой ставке. После завершения резерв заменяется точным списанием: - `completion_tokens_details.audio_tokens` → `audio_output_tokens`; - reasoning tokens → `reasoning_tokens`; - остальные completion tokens → `output_tokens`. Если положительная audio-output ставка отсутствует, запрос отклоняется до обращения к модели с кодом `audio_output_price_not_configured`. Token usage проходит через те же provider-statement, reconciliation, profitability, CSV и closing-document процессы, что и текстовое использование. ### Конфиденциальность и безопасность Аудиобайты и transcript передаются транзитом и не сохраняются в inference-записи, финансовой истории или прикладных логах. Сохраняются только token usage, стоимость, технические статусы и content-free идентификаторы сверки. Синтезированный голос может использоваться только в утверждённых организацией сценариях. Для имитации реального человека заранее получите необходимое согласие, маркируйте синтетический контент и запретите применение для социальной инженерии, подмены личности и обхода голосовой аутентификации. Клиентское приложение также не должно записывать SSE-body в access/error-логи. ### Ошибки - `audio_output_requires_stream` — аудио запрошено без `stream: true`; - `invalid_audio_output` — неверные modalities, отсутствует конфигурация или переданы лишние поля; - `unsupported_audio_output_format` — формат отсутствует в allowlist gateway; - `unsupported_model_capability` — модель не объявляет text+audio output; - `audio_output_price_not_configured` — не опубликован отдельный RUB-тариф; - `reconciliation_required` — поток оборвался после возможного upstream-использования. Машиночитаемый контракт находится в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## Атрибуция пользователей Источник: https://paipe.ru/docs/ai/end-user-attribution.md Поля `user` в Chat Completions, Responses и Embeddings позволяют связать расход с конечным пользователем клиентской системы, не передавая Paipe прямые идентификаторы. Это поле необязательно и поддерживается одинаково для обычных и потоковых запросов. Передавайте только собственный непрямой идентификатор длиной 1–128 символов: ```json { "model": "paipe/text-pro", "messages": [{"role": "user", "content": "Составь краткое резюме"}], "user": "account-7f31" } ``` Не передавайте ФИО, email, телефон, логин или иной прямой идентификатор. Значение должно быть UTF-8 строкой без пробелов по краям. Paipe нормализует Unicode и до резервирования средств заменяет значение на tenant-bound HMAC. Сырое значение: - не сохраняется в PostgreSQL, пресетах, usage и audit evidence; - не включается в нормальные application logs и telemetry; - не отправляется инфраструктурному поставщику модели; - не возвращается клиенту. В `paipe.end_user_ref` возвращается стабильная ссылка вида `eu_…`: ```json { "paipe": { "request_id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "end_user_ref": "eu_qZ7RkW8QzOJK6c88oTFxMs3ePip0EkGs5o-lpFVAsRg" } } ``` Она стабильна только внутри одной организации: одинаковое исходное значение в разных организациях получает разные ссылки. Ссылка доступна в `GET /v1/generation`, CSV-экспорте и может быть передана как `end_user_ref` в `GET /v1/usage` для агрегирования расхода одного пользователя. Фильтры намеренно не принимают сырые значения, чтобы они не попадали в URL и access logs. ### Эксплуатация ключа Production требует отдельный `END_USER_HMAC_KEY_BASE64`, декодирующийся ровно в 32 случайных байта. Он должен поступать из secret manager и быть одинаковым на всех активных нодах и площадках одной среды. Изменение ключа меняет все будущие `end_user_ref` и разрывает сопоставление с историей, поэтому его нельзя ротировать как обычный краткоживущий credential: сначала нужен отдельный план миграции и период совместимости. Доступ к ключу ограничивается application runtime; в БД хранится только 32-байтный HMAC. HMAC остаётся псевдонимизированными, а не анонимными данными. Его обработка и срок хранения должны быть отражены в модели угроз, реестре обработки данных и договорных основаниях организации. --- ## Analytics Query API Источник: https://paipe.ru/docs/ai/analytics.md `POST /v1/analytics/query` предоставляет B2B-интеграциям программируемую аналитику расходов и нагрузки без доступа к prompts, outputs, внутренним маршрутам или поставщикам. Требуется API-ключ со scope `usage:read`. Организация определяется только по ключу. Если ключ неизменяемо привязан к проекту, все запросы дополнительно ограничиваются этим проектом — переданный `project_ids` не может расширить область доступа. ### Пример запроса ```bash curl -X POST https://api.paipe.ru/v1/analytics/query \ -H "Authorization: Bearer $PAIPE_USAGE_KEY" \ -H "Content-Type: application/json" \ -d '{ "metrics": [ "requests", "input_tokens", "output_tokens", "billed_rub", "success_rate" ], "dimensions": ["project", "model", "operation"], "granularity": "day", "time_range": { "start": "2026-08-01T00:00:00Z", "end": "2026-08-12T00:00:00Z" }, "filters": { "models": ["paipe/text-pro"], "statuses": ["succeeded"], "project_ids": ["018f3a8f-4f67-7b21-a84d-09f18a1b6d90"] }, "order_by": {"metric": "billed_rub", "direction": "desc"}, "limit": 100 }' ``` Все поля необязательны. По умолчанию сервер возвращает `requests` и `billed_rub` за последние 30 суток без группировки, сортирует по первой метрике по убыванию и ограничивает ответ 100 строками. ### Разрешённый словарь Метрики: - `requests`, `succeeded_requests`; - `input_tokens`, `output_tokens`, `total_tokens`; - `billed_rub` — точная decimal string в рублях; - `avg_latency_ms` — decimal string без потери точности; - `success_rate` — decimal string от `0` до `1`. Измерения: `model`, `operation`, `status`, `project`. Гранулярность: `hour`, `day`, `week`, `month`; календарные границы рассчитываются в `Europe/Moscow`, неделя начинается в понедельник. Фильтры имеют только фиксированные поля `models`, `operations`, `statuses` и `project_ids`. SQL, произвольные выражения, provider names и пользовательский контент не принимаются. ### Пример ответа ```json { "object": "analytics.query", "data": [ { "dimensions": { "bucket": "2026-08-10T21:00:00Z", "model": "paipe/text-pro", "operation": "chat_completion", "project": { "id": "018f3a8f-4f67-7b21-a84d-09f18a1b6d90", "name": "Production", "cost_center_code": "AI-PROD" } }, "metrics": { "requests": 1842, "input_tokens": 2700000, "output_tokens": 640000, "billed_rub": "1725.84", "success_rate": "0.9989" } } ], "meta": { "metrics": ["requests", "input_tokens", "output_tokens", "billed_rub", "success_rate"], "dimensions": ["bucket", "project", "model", "operation"], "time_range": { "start": "2026-08-01T00:00:00Z", "end": "2026-08-12T00:00:00Z" }, "granularity": "day", "row_count": 1, "truncated": false, "timezone": "Europe/Moscow", "currency": "RUB" } } ``` ### Ограничения и эксплуатация - максимальный период — 366 суток; - максимальный `limit` — 1000 строк; - максимум четыре измерения и 100 значений в одном фильтре; - конец периода исключающий: `[start, end)`; - неизвестные поля и дубликаты отклоняются; - `meta.truncated=true` означает, что нужно сузить период или фильтры; - ответ всегда содержит `Cache-Control: no-store`. Для регулярной выгрузки больших реестров используйте CSV export из кабинета, а не увеличивайте число аналитических запросов. Метрики выполнения endpoint имеют только bounded label `outcome`; идентификаторы клиентов в Prometheus не попадают. Полный контракт опубликован в [`priv/static/openapi.yaml`](https://paipe.ru/openapi.yaml). --- ## События наблюдаемости Источник: https://paipe.ru/docs/ai/observability-broadcast.md Observability Broadcast передаёт в корпоративные системы наблюдаемости технические события завершённых генераций. Настройка доступна в кабинете организации по `/app/{organization_id}/observability` владельцу и администраторам; разработчики видят состояние только для чтения, а billing/viewer доступа не имеют. Это privacy-first, content-free канал. Он никогда не включает промпт, ответ, исходный `user`, IP-адрес, upstream-провайдера, upstream model ID или его request ID. Передаются публичный псевдоним модели, opaque request/API-key/project IDs, псевдонимизированные `end_user_ref`/`session_ref`, timestamps, latency, безопасный status/error class, usage и точная сумма в RUB. ### Получатели - `webhook` — JSON-событие с HMAC-SHA256 подписью; - `otlp_http_json` — OTLP/HTTP JSON span с bearer token. Endpoint обязан использовать HTTPS, не может содержать credentials, query или fragment и должен попадать в операторский allowlist `OBSERVABILITY_ALLOWED_HOST_SUFFIXES`. Перед каждой доставкой DNS разрешается заново; private, loopback, link-local, multicast и зарезервированные адреса отклоняются. Соединение закрепляется за уже проверенным публичным IP, сохраняя исходное имя для SNI, TLS certificate verification и HTTP Host. Это защищает от DNS rebinding и SSRF, но production egress firewall всё равно должен разрешать только согласованные destinations. Можно ограничить получателя набором API-ключей и выбрать 1%, 10%, 25%, 50% или 100% событий. Sampling детерминирован: при наличии session hash все запросы одной сессии получают одинаковое решение; иначе используется request ID. Получатель начинает с генераций, завершённых после его создания; автоматической отправки исторических событий нет. ### Webhook contract ```json { "schema_version": 1, "event_id": "delivery-uuid", "type": "ai.generation.completed", "occurred_at": "2026-08-12T10:00:00Z", "privacy_mode": true, "data": { "request_id": "request-uuid", "operation": "chat_completion", "status": "succeeded", "model": "paipe/model-alias", "streamed": false, "started_at": "2026-08-12T09:59:59Z", "completed_at": "2026-08-12T10:00:00Z", "latency_ms": 1000, "usage": {"input_tokens": 120, "output_tokens": 30}, "billed": {"currency": "RUB", "amount": "0.018"}, "failure": null, "api_key": {"id": "key-uuid"}, "project": {"id": "project-uuid"}, "end_user_ref": "eu_opaque", "session_ref": "ses_opaque" } } ``` Webhook получает заголовки: - `X-pAIpe-Event-Id`: стабильный ID доставки; - `X-pAIpe-Timestamp`: Unix seconds времени отправки; - `X-pAIpe-Signature`: `v1=`. Подписывается точная последовательность bytes `timestamp + "." + raw_request_body`. Получатель обязан сравнивать подпись в constant time, отклонять timestamps старше согласованного окна и делать обработку идемпотентной по `X-pAIpe-Event-Id`. ### Гарантии доставки Доставка асинхронная и как минимум однократная. HTTP 2xx считается успехом; остальные ответы и transport errors повторяются до 10 раз с bounded exponential backoff. После исчерпания попыток запись получает `exhausted`, а метрика `paipe_observability_delivery_count{outcome="exhausted"}` вызывает alert. Отключение destination немедленно останавливает ожидающие доставки. Секрет показывается только при вводе, шифруется AES-256-GCM отдельным ключом с destination-bound AAD и далее отображается только fingerprint. Ротация ключа шифрования выполняется через active+previous keyring; webhook secret меняется в кабинете отдельной операцией. --- ## Правила обработки содержимого Источник: https://paipe.ru/docs/ai/content-guardrails.md Content guardrails are a defense-in-depth control for text sent through the inference gateway. They do not create a legal basis for processing personal data and do not replace the customer contract, processing instructions, cross-border assessment, model allowlist or ZDR policy. ### Enforcement contract An organization owner or administrator publishes an immutable policy version at `/app/:organization_id/guardrails`. A version is either: - `enforce`, with 1–20 ordered `block` or `redact` rules; or - `disabled`, which explicitly records the decision to stop evaluation. Database triggers reject policy/rule updates and deletes, and reject adding a rule after the publication transaction has sealed that version. Every rule has a unique name, a pattern of at most 256 bytes and a fixed action. Matching is case-insensitive by default. `block` rules are evaluated against the original text before any redaction, so an earlier replacement cannot hide content from a blocking rule. `redact` replaces every accepted match with the fixed value `[REDACTED]`. Evaluation covers textual fields only: - Chat Completions message strings and text content blocks; - Responses `instructions`, string input, message text blocks and function outputs; - Embeddings text input and text blocks; - Rerank query and document text; - transcription prompt; - image-generation prompt and negative prompt. URLs, tool definitions, routing/session identifiers, base64 media, file blocks and binary content are not rewritten. The transformed payload passes the normal operation validator before pricing. Enforcement happens before inference admission, request creation, ledger reservation and provider dispatch. ### Safe regular-expression subset Patterns compile as Unicode expressions. The publisher rejects malformed patterns, empty matches, lookaround/extended constructs, backreferences, backtracking control verbs and obvious nested-quantifier forms. Runtime matches have explicit match and recursion limits and a request-wide maximum of 1,000 redactions. Any compile, resource-limit or evaluation anomaly fails closed with `503 content_guardrail_unavailable` and `Retry-After: 60`. This subset intentionally favors predictable operations over full PCRE expressiveness. Test a new pattern against representative non-production samples before publication. ### API behavior and evidence A blocked request returns: ```json { "error": { "type": "policy_error", "code": "content_guardrail_blocked", "message": "The request was blocked by the organization's content policy" } } ``` No inference request or financial reservation is created. For accepted requests, the immutable inference row records only the policy version ID, `none`/`redacted` outcome and bounded match count. It does not store the source text, matched value, rule name or transformed payload. The request fingerprint is derived from the original payload and policy version, so two different secrets that produce the same redacted text cannot share an idempotency key. Metrics expose only bounded global outcomes: - `paipe_guardrails_evaluation_count{outcome=...}`; - `paipe_guardrails_policy_published_count{mode=...}`. Organization IDs, API-key IDs, rule names and content are forbidden as metric labels. See the production runbook for fail-closed evaluation incidents.