Для AI-агентов: markdown этой страницы — /docs-content/cowork/off-peak.md индекс документации — /llms.txt

Выгодные часы в подписке Cowork/Code

В отдельные часы недели квота подписки расходуется медленнее — один и тот же запрос забирает меньшую долю месячного лимита. Ответы подписки показывают, действует ли скидка прямо сейчас и когда она начнётся.

Скидка применяется сама, включать её не нужно. Блок offPeak показывает то, что уже учтено при расходе квоты, чтобы приложение могло предложить перенести объёмную задачу на выгодный час.

Примеры

curl — личный ключ

Terminal
curl https://vibecode.bitrix24.tech/v1/cowork/state \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth-приложение

Terminal
curl https://vibecode.bitrix24.tech/v1/cowork/state \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — личный ключ

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/cowork/state', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const state = await res.json()
const off = state.offPeak

if (!off || !off.enabled) {
  console.log('Выгодные часы для этой подписки не действуют')
} else if (off.visible === 'now') {
  const discount = Math.round((1 - off.currentMultiplier) * 100)
  console.log(`Квота расходуется на ${discount}% медленнее ещё ${off.currentWindowEndsInHours} ч`)
} else if (off.visible === 'next' && off.nextAtOrBelow) {
  console.log(`Выгодный час начнётся через ${off.nextAtOrBelow.inHours} ч`)
}

JavaScript — OAuth-приложение

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/cowork/state', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const state = await res.json()

Поля ответа

Блок приезжает в двух ответах и различается составом.

Ответ Состав блока
ОтветGET /v1/cowork/state Состав блокаБлок целиком — вместе с сеткой grid и полем touSavedPct
ОтветGET /v1/cowork/me Состав блокаБлок без сетки и без touSavedPct

offPeak приходит в каждом успешном ответе обеих ручек, touSavedPct — в каждом успешном ответе GET /v1/cowork/state.

Поле Тип Описание
ПолеoffPeak Типobject ОписаниеБлок выгодных часов
ПолеoffPeak.enabled Типboolean ОписаниеДействуют ли выгодные часы для этой подписки. При false остальные поля пустые, все часы идут по полной цене
ПолеoffPeak.visible Типstring ОписаниеЧто показать пользователю: now — скидка действует прямо сейчас, next — заметная скидка начнётся в ближайшие часы, none — показывать нечего
ПолеoffPeak.timezone Типstring или null ОписаниеЧасовой пояс расписания — идентификатор из базы часовых поясов IANA, например Europe/Moscow. По нему считаются день недели и час
ПолеoffPeak.currentMultiplier Типnumber ОписаниеМножитель расхода квоты в текущий час, больше 0 и не больше 1. Значение 0.5 означает, что квота расходуется вдвое медленнее, значение 1 — без скидки
ПолеoffPeak.currentWindowEndsInHours Типnumber или null ОписаниеЧерез сколько часов расход перестанет быть таким же выгодным. null, если в пределах недели вперёд дороже не станет
ПолеoffPeak.nextAtOrBelow Типobject или null ОписаниеБлижайший час, скидка в котором достаточна, чтобы её показывать. null, когда такого часа нет в пределах недели вперёд
ПолеoffPeak.nextAtOrBelow.inHours Типnumber ОписаниеЧерез сколько часов наступит этот час
ПолеoffPeak.nextAtOrBelow.multiplier Типnumber ОписаниеМножитель расхода квоты в этом часе
ПолеoffPeak.perModel Типboolean Описаниеtrue, если расписание подобрано под одну модель, а не общее для всех моделей подписки
ПолеoffPeak.modelName Типstring или null ОписаниеНазвание модели, под которую подобрано расписание. null, когда расписание общее
ПолеoffPeak.grid Типarray или null ОписаниеСетка множителей grid[день][час]. Семь строк по 24 значения. День 0 — воскресенье, день 6 — суббота. Час — от 0 до 23 в часовом поясе timezone. Приходит только в GET /v1/cowork/state
ПолеoffPeak.nowCell Типobject или null ОписаниеЯчейка сетки, которой соответствует текущий момент. Считается на сервере, поэтому совпадает с currentMultiplier
ПолеoffPeak.nowCell.dow Типnumber ОписаниеДень недели, от 0 (воскресенье) до 6 (суббота)
ПолеoffPeak.nowCell.hour Типnumber ОписаниеЧас, от 0 до 23
ПолеtouSavedPct Типnumber или null ОписаниеКакую долю МЕСЯЧНОГО ОБЪЁМА подписки вернули выгодные часы за текущий расчётный период, в процентах с одним знаком после запятой, не больше 100. Приходит только в GET /v1/cowork/state

Пример ответа

Ответ GET /v1/cowork/state. Показаны блок выгодных часов и доля сэкономленного, остальные поля — в Состоянии подписки Cowork/Code.

JSON
{
  "offPeak": {
    "enabled": true,
    "visible": "now",
    "timezone": "Europe/Moscow",
    "currentMultiplier": 0.5,
    "currentWindowEndsInHours": 6,
    "nextAtOrBelow": { "inHours": 1, "multiplier": 0.5 },
    "perModel": false,
    "modelName": null,
    "grid": [
      [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],
      [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],
      [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],
      [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],
      [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],
      [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],
      [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]
    ],
    "nowCell": { "dow": 1, "hour": 3 }
  },
  "touSavedPct": 12.4
}

Тот же момент в ответе GET /v1/cowork/me — без сетки и без доли сэкономленного:

JSON
{
  "offPeak": {
    "enabled": true,
    "visible": "now",
    "timezone": "Europe/Moscow",
    "currentMultiplier": 0.5,
    "currentWindowEndsInHours": 6,
    "nextAtOrBelow": { "inHours": 1, "multiplier": 0.5 },
    "perModel": false,
    "modelName": null,
    "nowCell": { "dow": 1, "hour": 3 }
  }
}

Пример ответа при ошибке

404 — подписка не активирована:

JSON
{
  "success": false,
  "error": {
    "code": "COWORK_NOT_ACTIVATED",
    "message": "No active Cowork/Code subscription for this user+portal"
  }
}

Ошибки

HTTP Код Описание
HTTP401 КодMISSING_API_KEY ОписаниеНе передан заголовок X-Api-Key
HTTP401 КодINVALID_API_KEY ОписаниеКлюч не опознан: такой строки на платформе нет
HTTP403 КодINSUFFICIENT_SCOPE ОписаниеУ ключа нет скоупа vibe:cowork
HTTP404 КодCOWORK_NOT_ACTIVATED ОписаниеПодписка Cowork/Code не найдена для пары пользователь и портал
HTTP500 КодINVALID_TIER_CONFIGURATION ОписаниеКонфигурация тарифов на платформе некорректна
HTTP503 КодCOWORK_FEATURE_DISABLED ОписаниеCowork/Code отключён на уровне платформы

Полный список общих ошибок API — Ошибки.

Подсказка в отказе по исчерпанной квоте

Когда окно квоты подписки исчерпано, POST /v1/chat/completions отвечает 402 с кодом cowork_quota_exhausted. В теле такого отказа приезжает необязательное поле error.offPeakHint — через сколько часов блокировка снимется и какой множитель расхода будет действовать в этот момент. По нему приложение решает, достаточно ли просто подождать.

Поле Тип Описание
Полеerror.offPeakHint Типobject ОписаниеПодсказка о выгодном часе на момент разблокировки
Полеerror.offPeakHint.inHours Типnumber ОписаниеЧерез сколько часов снимется блокировка. Округляется вверх — тот же источник, что и у заголовка Retry-After
Полеerror.offPeakHint.multiplier Типnumber ОписаниеМножитель расхода квоты, который будет действовать в этот момент
JSON
{
  "error": {
    "message": "Cowork/Code quota exhausted for the 5h window. Wait until 2026-08-10T15:00:00.000Z or upgrade your tier.",
    "type": "insufficient_quota",
    "code": "cowork_quota_exhausted",
    "window": "5h",
    "resetAt": "2026-08-10T15:00:00.000Z",
    "nextTier": "PRO",
    "offPeakHint": { "inHours": 3, "multiplier": 0.5 }
  }
}

Подсказка приходит, только когда момент разблокировки попадает в час со скидкой. В остальных случаях ключа offPeakHint в теле нет вовсе — со значением null он не приходит.

Множитель считается ровно на момент разблокировки, ближайшее выгодное окно при этом не ищется. Если в этот час скидки не будет, подсказки не будет тоже — даже когда выгодный час наступит немного позже.

Известные особенности

Ветвите интерфейс по visible, а не по собственному порогу. Порог, начиная с которого скидку стоит показывать, платформа решает на своей стороне и наружу не отдаёт. Сравнение currentMultiplier с числом, вписанным в клиент, разойдётся с платформой при следующей настройке порога.

Множитель — коэффициент расхода, а не размер скидки. Значение 0.62 означает, что вызов забирает 62% от той доли квоты, которую он забрал бы без скидки, то есть расход снижен на 38%. Размер скидки считается как 1 - currentMultiplier.

nextAtOrBelow ищет заметную скидку, а не любое удешевление. Этим он отличается от поля nextWindow в Расписании выгодных часов: там ближайший строго более дешёвый час, здесь — ближайший час, скидка в котором достаточна для показа.

Блок молчит, пока подписка не активна. Приостановленная и отменённая подписка получает enabled: false — расписание к ней уже не применяется.

touSavedPct считается от месячного объёма подписки, а не от расхода. Знаменатель тот же, что у полосы месячной квоты, поэтому две доли читаются рядом: «израсходовано N%» и «выгодные часы вернули M%». Значение null приходит, только когда за текущий период ещё ничего не сэкономлено.

Смотрите также