For AI agents: markdown of this page — /docs-content-en/cowork/off-peak.md documentation index — /llms.txt

Off-peak hours in the Cowork/Code subscription

During certain hours of the week the subscription quota is consumed more slowly — the same request takes a smaller share of the monthly limit. The subscription responses show whether the discount applies right now and when it starts.

The discount applies on its own; there is nothing to switch on. The offPeak block reports what has already been taken into account when the quota was consumed, so an app can offer to move a bulk job to an off-peak hour. Off-peak hours are not in effect on this platform yet, so today the block does not arrive here at all.

Examples

curl — personal key

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

curl — OAuth application

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

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/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('Off-peak hours are not in effect for this subscription')
} else if (off.visible === 'now') {
  const discount = Math.round((1 - off.currentMultiplier) * 100)
  console.log(`Quota is consumed ${discount}% more slowly for another ${off.currentWindowEndsInHours} h`)
} else if (off.visible === 'next' && off.nextAtOrBelow) {
  console.log(`An off-peak hour starts in ${off.nextAtOrBelow.inHours} h`)
}

JavaScript — OAuth application

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

const state = await res.json()

Response fields

The block arrives in two responses, and its contents differ between them.

Response Block composition
ResponseGET /v1/cowork/state Block compositionThe whole block — together with the grid and the touSavedPct field
ResponseGET /v1/cowork/me Block compositionThe block without the grid and without touSavedPct

offPeak arrives in every successful response of both endpoints, and touSavedPct in every successful response of GET /v1/cowork/state.

Field Type Description
FieldoffPeak Typeobject DescriptionOff-peak hours block
FieldoffPeak.enabled Typeboolean DescriptionWhether off-peak hours are in effect for this subscription. When false, the remaining fields are empty and every hour is at full price
FieldoffPeak.visible Typestring DescriptionWhat to show the user: now — the discount applies right now, next — a meaningful discount starts within the next few hours, none — nothing to show
FieldoffPeak.timezone Typestring or null DescriptionSchedule time zone — an identifier from the IANA time zone database, for example UTC. The day of week and hour are computed against it
FieldoffPeak.currentMultiplier Typenumber DescriptionQuota-consumption multiplier for the current hour, greater than 0 and no more than 1. A value of 0.5 means the quota is consumed twice as slowly, a value of 1 means no discount
FieldoffPeak.currentWindowEndsInHours Typenumber or null DescriptionHow many hours until consumption stops being this favorable. null when it does not get more expensive within the next week
FieldoffPeak.nextAtOrBelow Typeobject or null DescriptionThe nearest hour whose discount is deep enough to be worth showing. null when there is no such hour within the next week
FieldoffPeak.nextAtOrBelow.inHours Typenumber DescriptionHow many hours until that hour arrives
FieldoffPeak.nextAtOrBelow.multiplier Typenumber DescriptionQuota-consumption multiplier in that hour
FieldoffPeak.perModel Typeboolean Descriptiontrue when the schedule is tailored to a single model rather than shared by all models of the subscription
FieldoffPeak.modelName Typestring or null DescriptionName of the model the schedule is tailored to. null when the schedule is shared
FieldoffPeak.grid Typearray or null DescriptionGrid of multipliers grid[day][hour]. Seven rows of 24 values. Day 0 is Sunday, day 6 is Saturday. The hour is 0 to 23 in the timezone time zone. Arrives only in GET /v1/cowork/state
FieldoffPeak.nowCell Typeobject or null DescriptionThe grid cell that the current moment maps to. Computed on the server, so it matches currentMultiplier
FieldoffPeak.nowCell.dow Typenumber DescriptionDay of week, from 0 (Sunday) to 6 (Saturday)
FieldoffPeak.nowCell.hour Typenumber DescriptionHour, from 0 to 23
FieldtouSavedPct Typenumber or null DescriptionWhat share of the subscription's MONTHLY ALLOWANCE the off-peak hours gave back over the current billing period, in percent with one decimal place, capped at 100. Arrives only in GET /v1/cowork/state

Response example

A GET /v1/cowork/state response. It shows the off-peak block and the saved share; the remaining fields are in Cowork/Code subscription state.

JSON
{
  "offPeak": {
    "enabled": true,
    "visible": "now",
    "timezone": "UTC",
    "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
}

The same moment in a GET /v1/cowork/me response — without the grid and without the saved share:

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

Error response example

404 — subscription not activated:

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

Errors

HTTP Code Description
HTTP401 CodeMISSING_API_KEY DescriptionThe X-Api-Key header was not passed
HTTP401 CodeINVALID_API_KEY DescriptionThe key is not recognized — no such key exists on the platform
HTTP403 CodeINSUFFICIENT_SCOPE DescriptionThe key lacks the vibe:cowork scope
HTTP404 CodeCOWORK_NOT_ACTIVATED DescriptionNo Cowork/Code subscription found for the user and portal
HTTP500 CodeINVALID_TIER_CONFIGURATION DescriptionThe tier configuration on the platform is invalid
HTTP503 CodeCOWORK_FEATURE_DISABLED DescriptionCowork/Code is disabled at the platform level

The full list of common API errors — Errors.

The hint in the exhausted-quota refusal

When a subscription quota window is exhausted, POST /v1/chat/completions responds with 402 and the code cowork_quota_exhausted. The body of that refusal carries an optional error.offPeakHint field — how many hours until the lockout ends and which consumption multiplier will be in effect at that moment. An app reads it to decide whether simply waiting is enough.

Field Type Description
Fielderror.offPeakHint Typeobject DescriptionHint about the off-peak hour at the moment the lockout ends
Fielderror.offPeakHint.inHours Typenumber DescriptionHow many hours until the lockout ends. Rounded up, from the same source as the Retry-After header
Fielderror.offPeakHint.multiplier Typenumber DescriptionThe quota-consumption multiplier that will be in effect at that moment
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 }
  }
}

The hint arrives only when the unblock moment falls into a discounted hour. Otherwise the offPeakHint key is absent from the body entirely — it never arrives as null. Off-peak hours are not in effect on this platform yet, so today the hint does not arrive here at all.

The multiplier is computed exactly at the unblock moment; the platform does not look for the nearest off-peak window. If that hour carries no discount, no hint arrives either — even when an off-peak hour starts a little later.

Known specifics

Branch the interface on visible, not on a threshold of your own. The threshold above which a discount is worth showing is decided on the platform side and is not exposed. Comparing currentMultiplier against a number baked into the client will diverge from the platform the next time that threshold is tuned.

The multiplier is a consumption coefficient, not the discount size. A value of 0.62 means the call takes 62% of the quota share it would take without a discount, that is, consumption is reduced by 38%. The discount size is computed as 1 - currentMultiplier.

nextAtOrBelow looks for a meaningful discount, not for any price drop. That is how it differs from the nextWindow field in the Off-peak schedule: there it is the nearest strictly cheaper hour; here it is the nearest hour whose discount is deep enough to show.

The block stays silent while the subscription is not active. A paused or cancelled subscription gets enabled: false — the schedule no longer applies to it.

touSavedPct is measured against the monthly allowance, not against consumption. The denominator is the same as for the monthly quota bar, so the two shares read side by side: "N% used" and "off-peak hours gave back M%". The value is null only when nothing has been saved yet in the current period.

See also