[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-ai\u002Fconsumption":3,"docs-tabs-ai\u002Fconsumption":6},{"content":4,"lastmod":5},"# Расход и лимиты\n\nСколько AI-ресурсов израсходовано, какая часть месячной квоты компании уже потрачена и в какие часы квота расходуется медленнее.\n\nСтатистика считается **по API-ключу**: токены, стоимость и разбивка по моделям за выбранный период. Квота — **по порталу**: общий месячный лимит компании, единый для всех её ключей. Выгодные часы — расписание скидок, которое замедляет расход этой квоты в определённые часы недели.\n\nСкоуп: `vibe:ai`\n\n## Операции\n\n- [Статистика использования](.\u002Fconsumption\u002Fusage.md) — `GET \u002Fv1\u002Fai\u002Fusage`\n- [AI-квота компании](.\u002Fconsumption\u002Fquota.md) — `GET \u002Fv1\u002Fai\u002Fquota`\n- [Расписание выгодных часов](.\u002Fconsumption\u002Foff-peak.md) — `GET \u002Fv1\u002Foff-peak`\n\n## Типовой сценарий\n\n1. Проверьте остаток квоты перед массовой обработкой: [`GET \u002Fv1\u002Fai\u002Fquota`](.\u002Fconsumption\u002Fquota.md). Поля `pctUsed` и `exhausted` позволяют предупредить пользователя до отказа `402`.\n2. Узнайте, когда квота расходуется медленнее: [`GET \u002Fv1\u002Foff-peak`](.\u002Fconsumption\u002Foff-peak.md), и перенесите задачи, которые терпят отсрочку, в дешёвые окна.\n3. После обработки сверьте расход по ключу: [`GET \u002Fv1\u002Fai\u002Fusage`](.\u002Fconsumption\u002Fusage.md).\n\n## Смотрите также\n\n- [AI Router](\u002Fdocs\u002Fai)\n- [Список моделей](\u002Fdocs\u002Fai\u002Fmodels\u002Flist)\n- [Лимиты запросов](\u002Fdocs\u002Fai\u002Fchat\u002Frate-limits)\n","2026-07-10",{"consumption\u002Fusage.md":7,"consumption\u002Fquota.md":8,"consumption\u002Foff-peak.md":9},"\n## Статистика использования\n\n`GET \u002Fv1\u002Fai\u002Fusage`\n\nВозвращает агрегированную статистику использования AI для текущего API-ключа: общие показатели за период, разбивку по моделям, последние 10 вызовов и группировку по типу учётных данных (`PLATFORM`, `PORTAL`, `USER`).\n\n## Параметры\n\n| Параметр | Тип | Обяз. | По умолч. | Описание |\n|----------|-----|:-----:|-----------|----------|\n| `days` (query) | number | нет | `30` | Период в днях. Допустимый диапазон: `1..90`. Значения вне диапазона автоматически приводятся к границам |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fusage?days=7\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fusage?days=7\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fusage?days=7', {\n  headers: { 'X-Api-Key': 'YOUR_API_KEY' },\n})\n\nconst { data } = await res.json()\nconsole.log(`За ${data.period.days} дней: ${data.totals.calls} вызовов, ${data.totals.totalTokens} токенов`)\ndata.byModel.forEach((m) => console.log(`  ${m.modelId}: ${m.calls} запросов, ${m.cost} Вайбов`))\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fusage?days=30', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { data } = await res.json()\nconsole.log('Стоимость за 30 дней:', data.totals.cost, 'Вайбов')\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.period.days` | number | Фактический период в днях (после ограничения 1..90) |\n| `data.period.since` | string | Начало периода в `ISO 8601` |\n| `data.totals.calls` | number | Общее количество вызовов за период (все статусы) |\n| `data.totals.promptTokens` | number | Сумма токенов входа |\n| `data.totals.completionTokens` | number | Сумма токенов ответа |\n| `data.totals.totalTokens` | number | Сумма всех токенов |\n| `data.totals.cost` | number | Общая стоимость в Вайбах |\n| `data.byModel` | array | Разбивка успешных вызовов по моделям, сортировка по убыванию количества |\n| `data.byModel[].modelId` | string | ID модели |\n| `data.byModel[].calls` | number | Количество вызовов |\n| `data.byModel[].promptTokens` | number | Токены входа |\n| `data.byModel[].completionTokens` | number | Токены ответа |\n| `data.byModel[].totalTokens` | number | Сумма токенов |\n| `data.byModel[].cost` | number | Стоимость в Вайбах |\n| `data.byModel[].audioSeconds` | number | Секунды расшифрованного аудио (Whisper). Для текстовых моделей — `0` |\n| `data.recentCalls` | array | Последние 10 вызовов любого статуса |\n| `data.recentCalls[].modelId` | string | ID модели |\n| `data.recentCalls[].promptTokens` | number | Токены входа |\n| `data.recentCalls[].completionTokens` | number | Токены ответа |\n| `data.recentCalls[].cost` | number | Стоимость вызова в Вайбах |\n| `data.recentCalls[].status` | string | Статус: `SUCCESS`, `ERROR`, `INCOMPLETE`, `FALLBACK_ORIGIN`, `DISABLED_REDIRECT` |\n| `data.recentCalls[].createdAt` | string | Время вызова в `ISO 8601` |\n| `data.byScope` | object | Разбивка по типу учётных данных провайдера, ключи: `PLATFORM`, `PORTAL`, `USER` |\n| `data.byScope.\u003Cscope>.calls` | number | Количество вызовов через этот тип учётных данных |\n| `data.byScope.\u003Cscope>.promptTokens` | number | Токены входа |\n| `data.byScope.\u003Cscope>.completionTokens` | number | Токены ответа |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"period\": {\n      \"days\": 7,\n      \"since\": \"2026-04-20T11:30:00.000Z\"\n    },\n    \"totals\": {\n      \"calls\": 142,\n      \"promptTokens\": 45200,\n      \"completionTokens\": 18300,\n      \"totalTokens\": 63500,\n      \"cost\": 12.5\n    },\n    \"byModel\": [\n      {\n        \"modelId\": \"bitrix\u002Fbitrixgpt-5.5\",\n        \"calls\": 98,\n        \"promptTokens\": 28000,\n        \"completionTokens\": 11000,\n        \"totalTokens\": 39000,\n        \"cost\": 0\n      },\n      {\n        \"modelId\": \"openai\u002Fgpt-4o\",\n        \"calls\": 44,\n        \"promptTokens\": 17200,\n        \"completionTokens\": 7300,\n        \"totalTokens\": 24500,\n        \"cost\": 12.5\n      }\n    ],\n    \"recentCalls\": [\n      {\n        \"modelId\": \"bitrix\u002Fbitrixgpt-5.5\",\n        \"promptTokens\": 120,\n        \"completionTokens\": 85,\n        \"cost\": 0,\n        \"status\": \"SUCCESS\",\n        \"createdAt\": \"2026-04-27T11:30:00.000Z\"\n      },\n      {\n        \"modelId\": \"openai\u002Fgpt-4o\",\n        \"promptTokens\": 350,\n        \"completionTokens\": 200,\n        \"cost\": 0.28,\n        \"status\": \"SUCCESS\",\n        \"createdAt\": \"2026-04-27T09:45:00.000Z\"\n      }\n    ],\n    \"byScope\": {\n      \"PLATFORM\": {\n        \"calls\": 98,\n        \"promptTokens\": 28000,\n        \"completionTokens\": 11000\n      },\n      \"USER\": {\n        \"calls\": 44,\n        \"promptTokens\": 17200,\n        \"completionTokens\": 7300\n      }\n    }\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n`403 scope_missing` — у API-ключа нет скоупа `vibe:ai`:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API key does not have the vibe:ai scope required for AI endpoints. Add vibe:ai scope to your API key in portal settings.\",\n    \"type\": \"invalid_request_error\",\n    \"code\": \"scope_missing\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `no_api_key` | Запрос пришёл без идентификатора API-ключа |\n| 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` |\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**`recentCalls` всегда содержит до 10 записей.** Они не зависят от параметра `days` — это просто последние 10 вызовов независимо от того, попадают ли они в выбранный период.\n\n**`byModel` учитывает только `SUCCESS`.** Разбивка по моделям не включает ошибочные вызовы. Общие счётчики `totals` — все вызовы (включая `ERROR`, `INCOMPLETE`).\n\n**Стоимость в Вайбах.** Поле `cost` — это стоимость в Вайбах (внутренняя валюта платформы), не в рублях и не в долларах. Модели с нулевой ценой в каталоге (большинство `bitrix\u002F*`) и BYOK дают `cost: 0`. Часть платформенных моделей платная — цена берётся из тарифной таблицы `AiModel.inputPriceVibes` \u002F `AiModel.outputPriceVibes`, посмотреть её можно в [`GET \u002Fv1\u002Fmodels`](\u002Fdocs\u002Fai\u002Fmodels\u002Flist).\n\n**`byScope.USER` — это вызовы через ваш BYOK.** Если вы используете подключённый BYOK-ключ — статистика попадает в `byScope.USER`. Платформенные модели — в `byScope.PLATFORM`. Если у портала настроены PORTAL-credentials — в `byScope.PORTAL`. Когда вызовов с каким-то scope не было — ключ просто отсутствует в объекте.\n\n## Смотрите также\n\n- [Статистика по ключу](\u002Fdocs\u002Fai\u002Fcredentials\u002Fusage)\n- [Список моделей](\u002Fdocs\u002Fai\u002Fmodels\u002Flist)\n- [AI Router](\u002Fdocs\u002Fai)\n","\n## AI-квота компании\n\n`GET \u002Fv1\u002Fai\u002Fquota`\n\nВозвращает состояние месячной AI-квоты портала, к которому привязан API-ключ: процент израсходованного лимита, дату сброса и разбивку по моделям — сколько запросов и токенов пришлось на каждую модель и какую долю месячного лимита она израсходовала.\n\nКвота — портальная: лимит общий для всей компании, а не per-ключ. Абсолютные значения лимита (в Вайбах) API не раскрывает — только проценты.\n\n## Параметры\n\nБез параметров.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fquota\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fquota\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fquota', {\n  headers: { 'X-Api-Key': 'YOUR_API_KEY' },\n})\n\nconst { data } = await res.json()\nconsole.log(`Квота использована на ${data.pctUsed}%, сброс ${data.resetAt}`)\ndata.byModel.forEach((m) => {\n  console.log(`  ${m.modelId}: ${m.calls} запросов, ${m.pctOfLimit ?? 0}% лимита`)\n})\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fai\u002Fquota', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { data } = await res.json()\nconsole.log(`Квота использована на ${data.pctUsed}%, сброс ${data.resetAt}`)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.pctUsed` | number | Процент израсходованной месячной квоты. Честное значение — не обрезается на 100: перерасход показывается как есть (например, `150`) |\n| `data.exhausted` | boolean | `true`, когда квота исчерпана |\n| `data.resetAt` | string \\| null | Дата сброса квоты в `ISO 8601` (скользящее 30-дневное окно). `null`, пока по порталу не было ни одного тарифицируемого AI-вызова |\n| `data.pacing` | object \\| null | Состояние равномерного расходования квоты (пейсинг). `null`, если пейсинг выключен для портала — не включён ни платформой, ни администратором (см. «Равномерное расходование (pacing)» ниже) |\n| `data.pacing.mode` | string | Режим реакции на превышение окна: `wallet`, `block` или `ignore` |\n| `data.pacing.active` | boolean | `true`, только если превышение окна прямо сейчас приведёт к `429`: энфорсмент включён на платформе и режим не `ignore`. `false` — режим наблюдения или `ignore`: окна только информируют, блокировок и списаний нет |\n| `data.pacing.day.pctUsed` | number | Расход суточного окна в процентах от его собственного лимита (не от месячной квоты) |\n| `data.pacing.day.resetAt` | string | Момент сброса суточного окна в `ISO 8601` |\n| `data.pacing.week.pctUsed` | number | Расход недельного окна в процентах от его собственного лимита |\n| `data.pacing.week.resetAt` | string | Момент сброса недельного окна в `ISO 8601` |\n| `data.period.start` | string | Начало текущего окна квоты в `ISO 8601` |\n| `data.byModel` | array | Разбивка по моделям за текущее окно, сортировка по убыванию количества вызовов |\n| `data.byModel[].modelId` | string | ID модели |\n| `data.byModel[].calls` | number | Количество успешных вызовов |\n| `data.byModel[].tokensIn` | number | Токены входа |\n| `data.byModel[].tokensOut` | number | Токены ответа |\n| `data.byModel[].audioSeconds` | number | Секунды расшифрованного аудио (Whisper). Для текстовых моделей — `0` |\n| `data.byModel[].pctOfLimit` | number \\| null | Доля месячного лимита, израсходованная этой моделью, в процентах (один знак после запятой). `null`, когда у портала нет положительного лимита |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"pctUsed\": 12,\n    \"exhausted\": false,\n    \"resetAt\": \"2026-07-31T18:50:39.633Z\",\n    \"pacing\": {\n      \"mode\": \"wallet\",\n      \"active\": false,\n      \"day\": { \"pctUsed\": 42, \"resetAt\": \"2026-07-10T21:00:00.000Z\" },\n      \"week\": { \"pctUsed\": 18, \"resetAt\": \"2026-07-13T21:00:00.000Z\" }\n    },\n    \"period\": { \"start\": \"2026-07-01T18:50:39.633Z\" },\n    \"byModel\": [\n      {\n        \"modelId\": \"bitrix\u002Fopenai\u002Fgpt-oss-120b\",\n        \"calls\": 63017,\n        \"tokensIn\": 58000000,\n        \"tokensOut\": 43000000,\n        \"audioSeconds\": 0,\n        \"pctOfLimit\": 10.9\n      },\n      {\n        \"modelId\": \"bitrix\u002Fbitrixgpt-5.5\",\n        \"calls\": 1240,\n        \"tokensIn\": 800000,\n        \"tokensOut\": 350000,\n        \"audioSeconds\": 0,\n        \"pctOfLimit\": 1.2\n      }\n    ]\n  }\n}\n```\n\n## Равномерное расходование (pacing)\n\nПейсинг — дополнительные суточный и недельный лимиты расхода AI-квоты, каждый в процентах от общего месячного лимита. Платформа может включать пейсинг для портала по умолчанию (без действий администратора); раскатка поэтапная, поэтому не каждый портал уже покрыт. Администратор портала может включить пейсинг сам в кабинете `\u002Fai`; если портал под платформенным default-on — только ужесточить лимиты: ослабить их или выключить пейсинг нельзя, пока портал управляется платформенными настройками по умолчанию. Пейсинг не меняет саму месячную квоту — он сглаживает пики, не позволяя потратить весь месячный лимит за один день или час.\n\nРежим реакции на превышение окна настраивается администратором и приходит в поле `pacing.mode`:\n\n| Режим | Поведение при превышении окна |\n|-------|-------------------------------|\n| `wallet` | Вызов проходит как оплачиваемое превышение лимита — списывается с денежного баланса портала, при наличии средств и свободного часового лимита превышений |\n| `block` | Вызов отклоняется `429` до сброса окна — оплачиваемое превышение недоступно |\n| `ignore` | Окно считается для мониторинга, вызовы не блокируются |\n\n### Поле `pacing` в ответе\n\nТекущее состояние пейсинга отдаётся в `data.pacing` (см. «Поля ответа» выше) — `null`, если пейсинг выключен для портала (не включён ни платформой, ни администратором):\n\n```json\n{\n  \"mode\": \"wallet\",\n  \"active\": false,\n  \"day\": { \"pctUsed\": 42, \"resetAt\": \"2026-07-10T21:00:00.000Z\" },\n  \"week\": { \"pctUsed\": 18, \"resetAt\": \"2026-07-13T21:00:00.000Z\" }\n}\n```\n\n`active: false` означает, что превышение окна не приводит к `429` — это информационный режим: лимиты окон показываются в ответе, но не отклоняют запросы (`429` в этом состоянии невозможен). Так бывает и в демо-режиме платформенного энфорсмента, и при `mode: \"ignore\"` — режиме, который платформа применяет к порталам под default-on. `active: true` — превышение окна прямо сейчас приведёт к отказу в вызове. Как и весь ответ `GET \u002Fv1\u002Fai\u002Fquota`, состояние пейсинга кэшируется — статус запаздывает до 30 секунд.\n\n### Ошибка при превышении окна\n\nКогда пейсинг активен и суточный или недельный лимит пробит, запросы к [чат-комплишенам](\u002Fdocs\u002Fai\u002Fchat\u002Fcompletions), [эмбеддингам](\u002Fdocs\u002Fai\u002Fembeddings) и [расшифровке аудио](\u002Fdocs\u002Fai\u002Faudio\u002Ftranscriptions) отвечают `429`:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"ai_pacing_limited\",\n    \"type\": \"rate_limit_exceeded\",\n    \"message\": \"AI pacing window exceeded for this portal. Wait for the window reset or adjust pacing settings in the cabinet.\",\n    \"reason\": \"day_window\",\n    \"overageDenied\": \"wallet_empty\",\n    \"resetAt\": \"2026-07-11T00:00:00.000Z\",\n    \"retryAfter\": 3600\n  }\n}\n```\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `reason` | string | Какое окно пробито: `day_window` или `week_window` |\n| `overageDenied` | string \\| null | Причина отказа в оплачиваемом превышении лимита. Присутствует в ответе всегда: `wallet_empty` — не хватает средств на балансе портала, `breaker` — сработал часовой предохранитель расхода сверх квоты, `wallet_off` — портал не может расходовать сверх лимита. `null` — в режиме `block`, где оплачиваемое превышение недоступно в принципе |\n| `resetAt` | string | Момент, когда окно сбросится и вызовы снова начнут проходить, в `ISO 8601` |\n| `retryAfter` | number | То же время в секундах — совпадает со значением заголовка ответа `Retry-After` |\n\n### Как реагировать\n\n- **Соблюдайте `Retry-After` и `resetAt`.** Повторный вызов раньше указанного времени ничего не ускорит — квота не станет доступнее.\n- **В режиме `wallet` смотрите `overageDenied`.** `429` в этом режиме означает не «пейсинг запрещает вызовы вообще», а «отказано именно в оплачиваемом превышении лимита» — например, `wallet_empty` сигнализирует, что стоит пополнить баланс портала.\n- **Это не то же самое, что `402 ai_quota_exhausted`.** Пейсинг ограничивает скорость расхода в рамках ещё не исчерпанной месячной квоты. Ошибка `402` — сигнал о полном исчерпании самой квоты. Подробнее про `402` — в [описании ошибок чата](\u002Fdocs\u002Fai\u002Fchat\u002Fcompletions).\n\n## Пример ответа при ошибке\n\n`403 scope_missing` — у API-ключа нет скоупа `vibe:ai`:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API key does not have the vibe:ai scope required for AI endpoints. Add vibe:ai scope to your API key in portal settings.\",\n    \"type\": \"invalid_request_error\",\n    \"code\": \"scope_missing\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` |\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Ключ не найден или отозван |\n| 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**`pctOfLimit` считается по моделям программы квоты.** Модель, не входящая в программу квоты (для неё не настроена тарифная политика), присутствует в `byModel` со счётчиками вызовов и токенов, но её `pctOfLimit` равен `0` — она не расходует квоту.\n\n**Разбивка не включает Cowork-трафик.** Вызовы, тарифицируемые персональной подпиской Cowork\u002FCode, не расходуют квоту компании и в разбивку не входят.\n\n**Сумма `pctOfLimit` может отличаться от `pctUsed`.** `pctUsed` читается из леджера квоты и отражает условия тарификации на момент вызова (включая скидку «выгодных часов», если она активна), а `pctOfLimit` — пиковая оценка: пересчёт по текущим тарифным политикам за окно, без учёта скидок. При смене политик в середине окна значения могут расходиться.\n\n**Ответ кэшируется на 30 секунд.** Счётчики обновляются с задержкой до 30 секунд — для мониторинга квоты этого достаточно, опрашивать чаще нет смысла.\n\n**При исчерпании квоты вызовы моделей отвечают `402 ai_quota_exhausted`.** Подробнее — в описании ошибок [чата](\u002Fdocs\u002Fai\u002Fchat). Чтобы предупредить пользователя заранее, опрашивайте `pctUsed` и `exhausted` до вызова модели, а не дожидайтесь отказа.\n\n**При срабатывании пейсинга вызовы моделей отвечают `429 ai_pacing_limited`.** Отдельно от `402 ai_quota_exhausted` — пейсинг ограничивает скорость расхода ещё не исчерпанной квоты. Подробнее — в разделе «Равномерное расходование (pacing)» выше.\n\n## Смотрите также\n\n- [Расписание выгодных часов](\u002Fdocs\u002Fai\u002Fconsumption\u002Foff-peak)\n- [Статистика использования](\u002Fdocs\u002Fai\u002Fconsumption\u002Fusage)\n- [Список моделей](\u002Fdocs\u002Fai\u002Fmodels\u002Flist)\n- [AI Router](\u002Fdocs\u002Fai)\n","\n## Расписание выгодных часов\n\n`GET \u002Fv1\u002Foff-peak`\n\nВозвращает расписание выгодных часов: насколько медленнее расходуется AI-квота компании в каждый час недели и когда наступит ближайшее окно со скидкой.\n\nСкидка применяется к расходу квоты — в выгодные часы один и тот же вызов забирает меньшую долю месячного лимита. Оплата за токены по кошельку скидку не получает. Эндпоинт предназначен для планирования: агент читает расписание и переносит массовые задачи, которые терпят отсрочку, в дешёвые окна.\n\n## Параметры\n\n| Параметр | Тип | Обяз. | По умолч. | Описание |\n|----------|-----|:-----:|-----------|---------|\n| `model` (query) | string | нет | — | Идентификатор модели из [`GET \u002Fv1\u002Fmodels`](\u002Fdocs\u002Fai\u002Fmodels\u002Flist). Возвращает расписание этой модели. Без параметра возвращается расписание, отмеченное платформой как основное |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foff-peak?model=bitrix\u002Fbitrixgpt-5.5\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foff-peak?model=bitrix\u002Fbitrixgpt-5.5\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst url = 'https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foff-peak?model=bitrix\u002Fbitrixgpt-5.5'\nconst res = await fetch(url, {\n  headers: { 'X-Api-Key': 'YOUR_API_KEY' },\n})\n\nconst schedule = await res.json()\n\nif (schedule.enabled && schedule.currentMultiplier \u003C 1) {\n  const discount = Math.round((1 - schedule.currentMultiplier) * 100)\n  console.log(`Сейчас выгодный час: квота расходуется на ${discount}% медленнее`)\n} else if (schedule.nextWindow) {\n  console.log(`Дешевле станет через ${schedule.nextWindow.inHours} ч`)\n}\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst url = 'https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foff-peak?model=bitrix\u002Fbitrixgpt-5.5'\nconst res = await fetch(url, {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst schedule = await res.json()\n```\n\n## Поля ответа\n\nУспешный ответ — сам объект расписания, без обёртки `success` и `data`.\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `enabled` | boolean | Действует ли расписание для запрошенной модели. При `false` все часы идут по полной цене, остальные поля пустые |\n| `timezone` | string \\| null | Часовой пояс расписания — идентификатор из базы часовых поясов IANA, например `Europe\u002FMoscow`. По нему считаются день недели и час |\n| `currentMultiplier` | number | Множитель расхода квоты в текущий час, больше `0` и не больше `1`. Значение `0.5` означает, что квота расходуется вдвое медленнее, значение `1` — без скидки |\n| `nextWindow` | object \\| null | Ближайший час, который строго дешевле текущего, в пределах недели вперёд. `null`, когда такого часа нет |\n| `nextWindow.inHours` | number | Через сколько часов наступит этот час |\n| `nextWindow.multiplier` | number | Множитель расхода квоты в этом часе |\n| `grid` | array \\| null | Сетка множителей `grid[день][час]`. Семь строк по 24 значения. День `0` — воскресенье, день `6` — суббота. Час — от `0` до `23` в часовом поясе `timezone` |\n| `nowCell` | object \\| null | Ячейка сетки, которой соответствует текущий момент. Считается на сервере, поэтому совпадает с `currentMultiplier` |\n| `nowCell.dow` | number | День недели, от `0` (воскресенье) до `6` (суббота) |\n| `nowCell.hour` | number | Час, от `0` до `23` |\n\n## Пример ответа\n\nРасписание действует:\n\n```json\n{\n  \"enabled\": true,\n  \"timezone\": \"Europe\u002FMoscow\",\n  \"currentMultiplier\": 1,\n  \"nextWindow\": { \"inHours\": 4, \"multiplier\": 0.87 },\n  \"grid\": [\n    [0.75, 0.87, 0.87, 0.87, 0.87, 0.87, 0.87, 0.87, 0.75, 0.75, 0.75, 0.75, 0.62, 0.5, 0.75, 0.87, 1, 1, 0.87, 0.87, 0.87, 0.75, 0.75, 0.75],\n    [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.62, 0.62, 0.62, 0.75, 0.75, 0.87, 0.87, 0.75, 0.75, 0.75, 0.75, 0.62, 0.5, 0.5],\n    [0.5, 0.5, 0.62, 0.62, 0.75, 0.62, 0.62, 0.62, 0.75, 0.75, 0.87, 1, 1, 0.87, 0.75, 0.87, 0.87, 0.75, 0.75, 0.62, 0.62, 0.62, 0.62, 0.62],\n    [0.75, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.62, 0.62, 0.75, 0.75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87],\n    [1, 1, 1, 1, 1, 0.87, 0.87, 0.87, 0.87, 1, 1, 1, 1, 1, 1, 0.87, 0.75, 0.75, 0.75, 0.87, 1, 1, 1, 1],\n    [1, 1, 1, 1, 1, 0.87, 0.87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87, 0.87, 0.75, 0.87],\n    [0.75, 0.62, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.62, 0.75, 0.75, 0.62, 0.62, 0.75, 0.75, 0.87, 0.87, 1, 1, 1, 1, 0.87]\n  ],\n  \"nowCell\": { \"dow\": 4, \"hour\": 11 }\n}\n```\n\nРасписание не действует — у модели его нет, либо выгодные часы отключены на платформе:\n\n```json\n{\n  \"enabled\": false,\n  \"timezone\": null,\n  \"currentMultiplier\": 1,\n  \"nextWindow\": null,\n  \"grid\": null,\n  \"nowCell\": null\n}\n```\n\n## Пример ответа при ошибке\n\n`401 MISSING_API_KEY` — не передан заголовок `X-Api-Key`:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"MISSING_API_KEY\",\n    \"message\": \"API key required. Pass via X-Api-Key header.\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Ключ не найден или отозван |\n| 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` |\n| 429 | `rate_limit_exceeded` | Превышен лимит запросов к AI-эндпоинтам. Время до сброса — в заголовке `Retry-After` |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Множитель — коэффициент расхода, а не размер скидки.** Значение `0.62` означает, что вызов забирает 62% от той доли квоты, которую он забрал бы без скидки, то есть расход снижен на 38%. Размер скидки считается как `1 - currentMultiplier`.\n\n**Указывайте модель.** Без параметра `model` эндпоинт отдаёт расписание, отмеченное платформой как основное. Пока основное расписание не назначено, такой вызов возвращает `enabled: false`, даже если у отдельных моделей скидки действуют.\n\n**Неизвестная модель не даёт ошибки.** Если у модели нет расписания или идентификатор не существует, приходит `200` с `enabled: false` и пустыми полями. Признак наличия скидок — поле `enabled`, а не код ответа.\n\n**Расписание меняется.** Платформа пересчитывает сетку по фактической нагрузке, поэтому перечитывайте расписание перед планированием, а не сохраняйте его надолго.\n\n**`nextWindow` ищет строго более дешёвый час.** Если текущий час уже самый дешёвый в пределах недели вперёд, поле равно `null`. Это не означает отсутствия скидки — смотрите `currentMultiplier`.\n\n**Скидка замедляет заполнение окон равномерного расходования.** Суточное и недельное окна растут на ту же величину расхода, что и месячная квота, то есть уже со скидкой. Перенос отложенных задач в выгодные часы отдаляет и `429 ai_pacing_limited`, и исчерпание месячной квоты.\n\n## Смотрите также\n\n- [AI-квота компании](\u002Fdocs\u002Fai\u002Fconsumption\u002Fquota)\n- [Список моделей](\u002Fdocs\u002Fai\u002Fmodels\u002Flist)\n- [Чат-комплишены](\u002Fdocs\u002Fai\u002Fchat\u002Fcompletions)\n- [AI Router](\u002Fdocs\u002Fai)\n"]