Ошибки и лимиты запросов
Все эндпоинты сообщают об ошибках в едином формате — с машиночитаемым кодом и ID запроса.
Ответ с ошибкой
Неудачный вызов возвращает success: false. Поле code стабильно и предназначено для программ, error — краткое сообщение на английском языке для людей, а request_id идентифицирует вызов в наших журналах. Если проблема во входных данных, поле param называет некорректный параметр.
Реальные примеры
Это настоящие ответы, полученные от API при формировании этой страницы.
{
"success": false,
"error": "coin required",
"code": "INVALID_PARAM",
"request_id": "cb-mwefrnxl-5e7dc77bd0"
}{
"success": false,
"code": "NOT_FOUND",
"error": "unknown endpoint: GET /api/this-endpoint-does-not-exist",
"request_id": "cb-mwefrnxl-ddc3046308"
}Коды ошибок
| Код | HTTP | Значение | Что делать |
|---|---|---|---|
| INVALID_PARAM | 400 | Отсутствует обязательный параметр, или значение не принимается. `param` называет параметр, если он известен. | Не повторяйте запрос без изменений; исправьте его. |
| UNAUTHORIZED | 401 | Заголовок `CB-API-KEY` был отправлен, но ключ неизвестен или отозван. Для публичных данных ключ не нужен — уберите заголовок или используйте действительный ключ. | Не повторяйте запрос без изменений. |
| FORBIDDEN | 403 | Маршрут не входит в публичный API (внутренний или только для аккаунта). | Не повторяйте запрос. |
| NOT_FOUND | 404 | Неизвестный маршрут, либо запрошенная монета / биржа / фонд не существует. | Не повторяйте запрос; сверьте путь и идентификаторы с каталогом. |
| RATE_LIMITED | 429 | Запросов больше, чем позволяет поминутный лимит. `Retry-After` указывает, сколько секунд нужно подождать. | Дождитесь истечения `Retry-After`, затем повторите запрос с нарастающей задержкой. |
| INTERNAL | 500 | Непредвиденная ошибка сервера. Сообщение намеренно общее; при обращении указывайте `request_id`. | Повторите запрос один раз через несколько секунд; если ошибка сохраняется, сообщите о ней, указав ID запроса. |
| UPSTREAM_FAILED | 503 | Источник данных, стоящий за этим эндпоинтом, не ответил вовремя. Устаревшие или подменные значения вместо него не возвращаются. | Повторите запрос с нарастающей задержкой; проверьте страницу статуса. |
| UNAVAILABLE | 501 / 503 | Набор данных временно не готов (прогрев кеша), либо у эндпоинта пока нет законного публичного источника. | Повторите запрос позже; каталог помечает эндпоинты, недоступные по проектному решению. |
| REQUEST_FAILED | 200 | Некоторые более старые эндпоинты отвечают HTTP 200 с `success: false`. Всегда проверяйте `success`, а не только статус HTTP. | Зависит от сообщения; считайте запрос неудачным. |
ID запроса
Каждый ответ содержит заголовок X-Request-Id. В ответах с ошибкой он дублируется в теле как request_id. Ответы, отданные из короткого пограничного кеша, повторяют ID того запроса, который их сформировал, поэтому одинаковые ID в последовательных вызовах означают, что получена кешированная копия.
Лимиты запросов
Лимиты действуют в расчёте на минуту: по IP-адресу для анонимных вызовов и по ключу, если передан действительный заголовок CB-API-KEY. Лимит запросов в минуту: 1200. Запросы иконок по пути /api/coin-icon не учитываются.
Заголовки лимита запросов
| Имя | Описание |
|---|---|
| X-Request-Id | Идентификатор этого запроса. Указывайте его в сообщениях об ошибках. |
| X-RateLimit-Limit | Число запросов, разрешённых в текущем минутном окне. |
| X-RateLimit-Remaining | Число запросов, оставшихся в текущем окне. |
| X-RateLimit-Reset | Время сброса окна в формате Unix, в секундах. |
| Retry-After | Передаётся с HTTP 429: сколько секунд нужно подождать перед повтором. |
| X-Cache | HIT, STALE или MISS для серверного кеша ответов. |
При превышении лимита
API отвечает HTTP 429 с кодом RATE_LIMITED. Подождите столько секунд, сколько указано в Retry-After, и повторите запрос. Опрос чаще, чем TTL кеша эндпоинта, возвращает тот же кешированный ответ, поэтому согласуйте интервал опроса с TTL, указанным на странице справочника.
Повтор с нарастающей задержкой
async function getJson(url, tries = 4) {
for (let i = 0; i < tries; i++) {
const res = await fetch(url);
if (res.status === 429 || res.status >= 500) {
const wait = Number(res.headers.get("Retry-After")) || 2 ** i;
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
const body = await res.json();
if (body.success === false) {
throw new Error(body.code + ": " + body.error + " (" + body.request_id + ")");
}
return body;
}
throw new Error("gave up after " + tries + " attempts");
}Отсутствие данных — не ошибка
Если параметры корректны, но законного публичного источника данных нет, вызов завершается успешно с HTTP 200: поля значений равны null, meta.quality имеет значение UNAVAILABLE, а причина указана в coverage.unavailable. Отображайте такое значение прочерком. Не преобразуйте его в 0.
Устаревшие данные
Если коллектор отстаёт, эндпоинты продолжают отдавать последние сохранённые значения с meta.is_stale: true, пока те не выйдут за окно пригодности; после этого значения исключаются из агрегатов и перечисляются в coverage.stale_excluded.