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

Off-peak schedule

GET /v1/off-peak

Returns the off-peak schedule: how much more slowly the company AI quota is consumed during each hour of the week and when the next discounted window arrives.

The discount applies to quota consumption — during off-peak hours the same call takes a smaller share of the monthly limit. Token payments from the wallet do not receive the discount. The endpoint is meant for planning: an agent reads the schedule and moves deferrable bulk tasks into the cheap windows.

Parameters

Parameter Type Required Default Description
model (query) string no Model identifier from GET /v1/models. Returns the schedule for that model. Without this parameter, returns the schedule the platform marked as the main one

Examples

curl — personal key

Terminal
curl "https://vibecode.bitrix24.com/v1/off-peak?model=bitrix/bitrixgpt-5.5" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

Terminal
curl "https://vibecode.bitrix24.com/v1/off-peak?model=bitrix/bitrixgpt-5.5" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — personal key

javascript
const url = 'https://vibecode.bitrix24.com/v1/off-peak?model=bitrix/bitrixgpt-5.5'
const res = await fetch(url, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const schedule = await res.json()

if (schedule.enabled && schedule.currentMultiplier < 1) {
  const discount = Math.round((1 - schedule.currentMultiplier) * 100)
  console.log(`Off-peak hour now: quota is consumed ${discount}% more slowly`)
} else if (schedule.nextWindow) {
  console.log(`Cheaper in ${schedule.nextWindow.inHours} h`)
}

JavaScript — OAuth application

javascript
const url = 'https://vibecode.bitrix24.com/v1/off-peak?model=bitrix/bitrixgpt-5.5'
const res = await fetch(url, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const schedule = await res.json()

Response fields

The successful response is the schedule object itself, without a success and data wrapper.

Field Type Description
enabled boolean Whether a schedule is in effect for the requested model. When false, every hour is at full price and the remaining fields are empty
timezone string | null Schedule timezone — an identifier from the IANA time zone database, for example UTC. The day of week and hour are computed against it
currentMultiplier number Quota-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
nextWindow object | null The nearest hour strictly cheaper than the current one, within a week ahead. null when there is no such hour
nextWindow.inHours number How many hours until that hour arrives
nextWindow.multiplier number Quota-consumption multiplier in that hour
grid array | null Grid 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
nowCell object | null The grid cell that the current moment maps to. Computed on the server, so it matches currentMultiplier
nowCell.dow number Day of week, from 0 (Sunday) to 6 (Saturday)
nowCell.hour number Hour, from 0 to 23

Response example

The schedule is in effect:

JSON
{
  "enabled": true,
  "timezone": "UTC",
  "currentMultiplier": 1,
  "nextWindow": { "inHours": 4, "multiplier": 0.87 },
  "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": 4, "hour": 11 }
}

The schedule is not in effect — the model has none, or off-peak hours are disabled on the platform:

JSON
{
  "enabled": false,
  "timezone": null,
  "currentMultiplier": 1,
  "nextWindow": null,
  "grid": null,
  "nowCell": null
}

Error response example

401 MISSING_API_KEY — the X-Api-Key header is missing:

JSON
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key required. Pass via X-Api-Key header."
  }
}

Errors

HTTP Code Description
401 MISSING_API_KEY The X-Api-Key header is missing
401 INVALID_API_KEY Key not found or revoked
403 scope_missing The API key lacks the vibe:ai scope
429 rate_limit_exceeded AI endpoint request limit exceeded. Time until reset is in the Retry-After header

The full list of common API errors — Errors.

Known specifics

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.

Pass the model. Without the model parameter the endpoint returns the schedule the platform marked as the main one. Until a main schedule is assigned, such a call returns enabled: false even when individual models do have discounts.

An unknown model does not raise an error. If a model has no schedule or the identifier does not exist, a 200 arrives with enabled: false and empty fields. The presence of discounts is signaled by the enabled field, not by the response code.

The schedule changes. The platform recomputes the grid against actual load, so re-read the schedule before planning rather than storing it for a long time.

nextWindow looks for a strictly cheaper hour. If the current hour is already the cheapest within a week ahead, the field is null. This does not mean there is no discount — check currentMultiplier.

The discount also slows down the pacing windows. The daily and weekly windows grow by the same discounted amount as the monthly quota. Moving deferrable jobs into the off-peak hours postpones both the 429 ai_pacing_limited response and the exhaustion of the monthly quota.

See also