> ## Индекс документации  
> Получите полный индекс документации по адресу: https://api.vega.chat/docs/llms.txt  
> Используйте этот файл, чтобы узнать о всех доступных страницах перед дальнейшим изучением.

# Ограничения

> Кредитные лимиты и лимиты запросов

```javascript
export const Variant = {
  Free: 'free'
};

export const sep = ':';

export const HTTPStatus = {
  S100_Continue: 100,
  S101_Switching_Protocols: 101,
  S102_Processing: 102,
  S200_OK: 200,
  S201_Created: 201,
  S202_Accepted: 202,
  S203_Non_Authoritative_Information: 203,
  S204_No_Content: 204,
  S205_Reset_Content: 205,
  S206_Partial_Content: 206,
  S207_Multi_Status: 207,
  S208_Already_Reported: 208,
  S300_Multiple_Choices: 300,
  S301_Moved_Permanently: 301,
  S302_Found: 302,
  S303_See_Other: 303,
  S304_Not_Modified: 304,
  S305_Use_Proxy: 305,
  S307_Temporary_Redirect: 307,
  S308_Permanent_Redirect: 308,
  S400_Bad_Request: 400,
  S401_Unauthorized: 401,
  S402_Payment_Required: 402,
  S403_Forbidden: 403,
  S404_Not_Found: 404,
  S405_Method_Not_Allowed: 405,
  S406_Not_Acceptable: 406,
  S407_Proxy_Authentication_Required: 407,
  S408_Request_Timeout: 408,
  S409_Conflict: 409,
  S410_Gone: 410,
  S411_Length_Required: 411,
  S412_Precondition_Failed: 412,
  S413_Payload_Too_Large: 413,
  S414_URI_Too_Long: 414,
  S415_Unsupported_Media_Type: 415,
  S416_Range_Not_Satisfiable: 416,
  S417_Expectation_Failed: 417,
  S418_Im_a_teapot: 418,
  S421_Misdirected_Request: 421,
  S422_Unprocessable_Entity: 422,
  S423_Locked: 423,
  S424_Failed_Dependency: 424,
  S425_Too_Early: 425,
  S426_Upgrade_Required: 426,
  S428_Precondition_Required: 428,
  S429_Too_Many_Requests: 429,
  S431_Request_Header_Fields_Too_Large: 431,
  S451_Unavailable_For_Legal_Reasons: 451,
  S498_Invalid_Token: 498,
  S499_Client_Closed_Request: 499,
  S500_Internal_Server_Error: 500,
  S501_Not_Implemented: 501,
  S502_Bad_Gateway: 502,
  S503_Service_Unavailable: 503,
  S504_Gateway_Timeout: 504,
  S505_HTTP_Version_Not_Supported: 505,
  S506_Variant_Also_Negotiates: 506,
  S507_Insufficient_Storage: 507,
  S508_Loop_Detected: 508,
  S510_Not_Extended: 510,
  S511_Network_Authentication_Required: 511,
  S520_Web_Server_Returned_Unknown_Error: 520,
  S521_Web_Server_Is_Down: 521,
  S522_Connection_Timed_Out: 522,
  S523_Origin_Unreachable: 523,
  S524_A_Timeout_Occurred: 524,
  S525_SSL_Handshake_Failed: 525,
  S526_Invalid_SSL_Certificate: 526,
  S529_Overloaded: 529,
  S530_Origin_DNS_Error: 530
};

export const FREE_MODEL_RATE_LIMIT_RPM = 20;

export const FREE_MODEL_NO_CREDITS_RPD = 50;

export const FREE_MODEL_HAS_CREDITS_RPD = 1000;

export const FREE_MODEL_CREDITS_THRESHOLD = 10;

export const API_KEY_REF = '<OPENROUTER_API_KEY>';

export const StatusCode = ({code}) => {
  const [popupPosition, setPopupPosition] = useState(null);
  const openPopup = event => {
    const rect = event.currentTarget.getBoundingClientRect();
    const width = 288;
    const margin = 8;
    const left = Math.min(Math.max(rect.left + rect.width / 2 - width / 2, margin), window.innerWidth - width - margin);
    setPopupPosition({
      left,
      top: rect.bottom + margin,
      width
    });
  };
  const closePopup = () => setPopupPosition(null);
  const STATUS_CODE_INFO = {
    200: {
      name: 'OK',
      description: 'The request succeeded. For streaming responses, errors occurring after this status is sent arrive as SSE events instead.'
    },
    400: {
      name: 'Bad Request',
      description: 'The request is invalid or missing required parameters, or was blocked by CORS.'
    },
    401: {
      name: 'Unauthorized',
      description: 'Invalid credentials — the API key is missing, invalid, disabled, or the OAuth session expired.'
    },
    402: {
      name: 'Payment Required',
      description: 'Your account or API key has insufficient credits. Add credits to bring your balance above zero, or check per-key credit limits.'
    },
    403: {
      name: 'Forbidden',
      description: 'Insufficient permissions, a guardrail block, or the input was flagged by moderation.'
    },
    404: {
      name: 'Not Found',
      description: 'The requested resource does not exist.'
    },
    408: {
      name: 'Request Timeout',
      description: 'The request timed out before completing.'
    },
    429: {
      name: 'Too Many Requests',
      description: 'You are being rate limited — either by an OpenRouter platform limit (free-model caps, DDoS protection) or by the upstream provider. Retry with exponential backoff and honor the Retry-After header when present.'
    },
    500: {
      name: 'Internal Server Error',
      description: 'Something went wrong on the server while handling the request.'
    },
    502: {
      name: 'Bad Gateway',
      description: 'The chosen model is down or the provider returned an invalid response.'
    },
    503: {
      name: 'Service Unavailable',
      description: 'No available model provider meets your routing requirements. Consider relaxing provider preferences or adding fallback models.'
    }
  };
  const info = STATUS_CODE_INFO[code];
  if (!info) {
    return <code>{code}</code>;
  }
  return <span className="relative inline-block" onMouseEnter={openPopup} onMouseLeave={closePopup} onFocus={openPopup} onBlur={closePopup}>
      <code tabIndex={0} aria-label={`HTTP ${code} ${info.name}: ${info.description}`} className="cursor-help underline decoration-dotted underline-offset-4">
        {code}
      </code>
      {popupPosition && <span role="tooltip" className="fixed z-50 block rounded-lg border border-gray-950/10 bg-white p-3 text-left shadow-lg dark:border-white/10 dark:bg-gray-900" style={{
    left: popupPosition.left,
    top: popupPosition.top,
    width: popupPosition.width
  }}>
          <span className="mb-1 flex items-baseline gap-2">
            <code className="text-sm font-semibold">{code}</code>
            <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">
              {info.name}
            </span>
          </span>
          <span className="block text-xs font-normal leading-relaxed text-gray-600 dark:text-gray-400">
            {info.description}
          </span>
        </span>}
    </span>;
};

export const Template = ({children, data}) => {
  const replace = s => s.replace(/\{\{(\w+)\}\}/g, (_, k) => (k in data) ? data[k] : `{{${k}}}`);
  const leafText = node => typeof node === 'string' ? node : node?.$$typeof && typeof node.props?.children === 'string' ? node.props.children : null;
  const collapseTokens = nodes => {
    const out = [];
    let i = 0;
    while (i < nodes.length) {
      const ta = leafText(nodes[i]);
      const tb = leafText(nodes[i + 1]);
      const tc = leafText(nodes[i + 2]);
      if (ta != null && tb != null && tc != null) {
        const m = (ta + tb + tc).match(/^([\s\S]*)\{\{(\w+)\}\}([\s\S]*)$/);
        if (m && (m[2] in data)) {
          out.push(m[1] + data[m[2]] + m[3]);
          i += 3;
          continue;
        }
      }
      out.push(nodes[i]);
      i++;
    }
    return out;
  };
  const process = node => {
    if (typeof node === 'string') return replace(node);
    if (Array.isArray(node)) return collapseTokens(node.map(process));
    if (node && typeof node === 'object') {
      if (node.$$typeof) return {
        ...node,
        props: process(node.props)
      };
      return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, process(v)]));
    }
    return node;
  };
  return <>{process(children)}</>;
};

<Tip>
  Создание дополнительных аккаунтов или ключей API не повлияет на ваши лимиты запросов, так как мы управляем ёмкостью глобально. Мы, однако, имеем разные лимиты запросов для разных моделей, так что вы можете распределять нагрузку таким образом, если столкнётесь с проблемами.
</Tip>

API VEGA enforces two kinds of limits:

| Тип лимита                     | Что регулирует                                                               | Ошибка при превышении                                 | Где проверить                                   |
| ------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------ |
| [Кредитные лимиты](#credit-limits) | Сколько вы можете потратить (баланс аккаунта и лимиты кредитов на каждый ключ) | <StatusCode code={HTTPStatus.S402_Payment_Required} /> | `GET /api/v1/key` → `limit_remaining`          |
| [Лимиты запросов](#rate-limits) | Сколько запросов вы можете сделать (лимиты запросов бесплатных моделей и защита от DDoS) | <StatusCode code={HTTPStatus.S429_Too_Many_Requests} /> | `X-RateLimit-*` заголовки в ответе об ошибке   |

## Проверка ваших лимитов

Чтобы проверить лимит запросов или оставшиеся кредиты на ключе API, выполните GET‑запрос к `https://api.vega.chat/api/v1/key`.

<Template data={{ API_KEY_REF }}>
  <CodeGroup>
    ```typescript title="TypeScript SDK" lines theme={null}
    import { OpenRouter } from '@openrouter/sdk';

    const openRouter = new OpenRouter({
      apiKey: '{{API_KEY_REF}}',
    });

    const keyInfo = await openRouter.apiKeys.getCurrent();
    console.log(keyInfo);
    ```

    ```python title="Python" lines theme={null}
    import requests
    import json

    response = requests.get(
      url="https://openrouter.ai/api/v1/key",
      headers={
        "Authorization": f"Bearer {{API_KEY_REF}}"
      }
    )

    print(json.dumps(response.json(), indent=2))
    ```

    ```typescript title="TypeScript (Raw API)" lines theme={null}
    const response = await fetch('https://openrouter.ai/api/v1/key', {
      method: 'GET',
      headers: {
        Authorization: 'Bearer {{API_KEY_REF}}',
      },
    });

    const keyInfo = await response.json();
    console.log(keyInfo);
    ```
  </CodeGroup>
</Template>

Если вы отправите действительный ключ API, вы должны получить ответ в следующем виде:

```typescript title="TypeScript" expandable lines theme={null}
type Key = {
  data: {
    label: string;
    limit: number | null; // Credit limit for the key, or null if unlimited
    limit_reset: string | null; // Type of limit reset for the key, or null if never resets
    limit_remaining: number | null; // Remaining credits for the key, or null if unlimited
    include_byok_in_limit: boolean;  // Whether to include external BYOK usage in the credit limit

    usage: number; // Number of credits used (all time)
    usage_daily: number; // Number of credits used (current UTC day)
    usage_weekly: number; // ... (current UTC week, starting Monday)
    usage_monthly: number; // ... (current UTC month)

    byok_usage: number; // Same for external BYOK usage
    byok_usage_daily: number;
    byok_usage_weekly: number;
    byok_usage_monthly: number;

    is_free_tier: boolean; // Whether the user has paid for credits before
    // rate_limit: { ... } // A deprecated object in the response, safe to ignore
  };
};
```

## Кредитные лимиты

Кредитные лимиты определяют, сколько вы можете потратить. Они берутся из двух источников:

1. **Баланс аккаунта**, ваши доступные кредиты по всему аккаунту. Если у вашего аккаунта отрицательный кредитный баланс, вы можете увидеть ошибки <StatusCode code={HTTPStatus.S402_Payment_Required} />, включая для бесплатных моделей. Добавление кредитов, чтобы ваш баланс стал положительным, позволит вам снова использовать эти модели.
2. **Кредитные лимиты на каждый ключ**, необязательный лимит расходов, настроенный для отдельного ключа API. Поля `limit`, `limit_reset` и `limit_remaining` в ответе `GET /api/v1/key`, приведённом выше, описывают этот лимит и сколько его осталось.

### Обработка ошибок 402

Для решения ошибок <StatusCode code={HTTPStatus.S402_Payment_Required} />:

* **Добавьте кредиты**, чтобы ваш баланс аккаунта стал положительным.
* **Проверьте лимиты на каждый ключ.** Если `limit_remaining` на ключе исчерпан, увеличьте кредитный лимит ключа или подождите его сброса (см. `limit_reset`).
* **Следите проактивно.** Вызывайте `GET /api/v1/key`, как показано выше, чтобы отслеживать `limit_remaining` и использование до того, как запросы начнут падать.

## Лимиты запросов

Лимиты запросов определяют, сколько запросов вы можете сделать. Существует несколько лимитов запросов, которые применяются к определённым типам запросов, независимо от статуса аккаунта:

1. **Лимиты бесплатного использования**: Если вы используете бесплатный вариант модели (с ID, заканчивающимся на <code>{sep}{Variant.Free}</code>), применяются следующие лимиты:

| Кредиты, купленные (за всё время) | Запросов в минуту | Запросов в день |
| ----------------------------------- | ----------------- | ---------------- |
| Меньше {FREE_MODEL_CREDITS_THRESHOLD} | {FREE_MODEL_RATE_LIMIT_RPM} | {FREE_MODEL_NO_CREDITS_RPD} |
| Не менее {FREE_MODEL_CREDITS_THRESHOLD} | {FREE_MODEL_RATE_LIMIT_RPM} | {FREE_MODEL_HAS_CREDITS_RPD} |

2. **Защита от DDoS**: Защита DDoS от Cloudflare будет блокировать запросы, которые значительно превышают разумное использование.

### Обработка ошибок 429

Запросы, отклонённые с ошибкой <StatusCode code={HTTPStatus.S429_Too_Many_Requests} />, завершаются стандартным [ответом об ошибке](/docs/api_reference/errors-and-debugging):

```json lines theme={null}
{
  "error": {
    "code": 429,
    "message": "Rate limit exceeded",
    "metadata": {
      "error_type": "rate_limit_exceeded"
    }
  }
}
```

Ошибка <StatusCode code={HTTPStatus.S429_Too_Many_Requests} /> может возникнуть из двух мест:

1. **API VEGA**, когда вы достигаете одного из вышеуказанных лимитов платформы (лимиты запросов бесплатных моделей в минуту или в день, или защита от DDoS).
2. **Поставщик upstream**, когда поставщик, обслуживающий ваш запрос, ограничивает количество запросов или находится на пределе ёмкости. В этом случае `error.metadata.provider_code` содержит оригинальный код ошибки поставщика, если он доступен, а [fallback routing](/docs/guides/routing/provider-selection) автоматически переходит к другим поставщикам той же модели до того, как ошибка дойдёт до вас. Вы также можете указать [fallback models](/docs/guides/routing/model-fallbacks), чтобы попробовать другую модель, когда все поставщики первой модели исчерпаны.

<Note>
  Успешные ответы инференса не включают заголовки `X-RateLimit-*`. Когда API VEGA сам возвращает ошибку <StatusCode code={HTTPStatus.S429_Too_Many_Requests} /> из-за лимита платформы, ответ об ошибке содержит заголовки `X-RateLimit-Limit`, `X-RateLimit-Remaining` и `X-RateLimit-Reset`, описывающие достигнутый лимит. Когда каждый попытанный поставщик вернул подсказку о повторе, ответ об ошибке также содержит заголовок `Retry-After`. Чтобы отслеживать оставшуюся квоту до достижения лимита, вызывайте `GET /api/v1/key`, как показано выше.
</Note>

Для решения ошибок <StatusCode code={HTTPStatus.S429_Too_Many_Requests} />:

* **Повторите запрос с экспоненциальным бэкофом.** Лимиты запросов являются временными; подождите и повторите запрос вместо мгновенной повторной отправки. Соблюдайте заголовок `Retry-After`, если он присутствует.
* **Для бесплатных вариантов**, приобретите как минимум {FREE_MODEL_CREDITS_THRESHOLD} кредитов, чтобы увеличить ваш дневной лимит, или переключитесь на платный вариант модели, у которого нет лимита запросов на уровне платформы.
* **Для лимитов со стороны поставщика**, добавьте [fallback models](/docs/guides/routing/model-fallbacks) или ослабьте [provider routing preferences](/docs/guides/routing/provider-selection), чтобы больше поставщиков могли обслуживать запрос.

#### Промежуточные лимиты запросов

Если лимит запросов достигается после начала стриминга, ошибка приходит как SSE‑событие с `finish_reason: "error"` вместо HTTP‑ошибки <StatusCode code={HTTPStatus.S429_Too_Many_Requests} />, поскольку статус <StatusCode code={HTTPStatus.S200_OK} /> уже был отправлен:

```text lines theme={null}
data: {"id":"cmpl-abc123","object":"chat.completion.chunk","created":1234567890,"model":"openai/gpt-4o","provider":"openai","error":{"code":429,"message":"Rate limit exceeded"},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}
```

Смотрите [Handling Errors During Streaming](/docs/api_reference/streaming#handling-errors-during-streaming) для подробностей и примеров кода.