Ошибки первого дня
Всё из этого списка случается почти с каждым, обычно в первые сутки. Формат одинаковый: симптом → причина → починка. Ошибки идут от частых к коварным.
401 на ключе, который точно верный #
Пробел или перенос строки в скопированном ключе. Ключ показывается один раз, копируют его в спешке. Проверка: длина строки в вашей переменной равна длине ключа на экране создания.
Нет слова Bearer. Заголовок — Authorization: Bearer lms_live_…, не голый
ключ.
Ключ отозван. Список ключей в настройках показывает состояние и когда ключ использовался последний раз — если «только что», а у вас 401, вы смотрите не на тот ключ.
403 при верной аутентификации #
Не хватает права. В ответе сказано, какого именно, — читайте тело, а не
только код. Не добавляйте * «чтобы работало»: право добавляется одно, названное.
Ключ сужен до курса. Ключ, ограниченный одним курсом, получает 403 на чужих — это не поломка, это его назначение.
404 на объекте, который есть #
Он вне видимости ключа. «Нет» и «не видно вам» снаружи неразличимы намеренно — иначе перебором можно узнать, какие объекты существуют.
Идентификатор не того типа. Смотрите на префикс: ord_ в адресе платежей —
это 404, и по префиксу причина видна за секунду. Ради этого префиксы и существуют.
Фильтр «не работает» — а на самом деле работает не тот #
Самая коварная ошибка списка, потому что она тихая.
Квадратные скобки и плюс в строке запроса должны быть закодированы: %5B, %5D,
%2B. Незакодированный + в дате читается как пробел — дата молча
становится другой, запрос успешно возвращает не тот набор данных, и выгрузка
выглядит правильной.
# Неверно: paid_at[gte]=2026-07-01T00:00:00+03:00
# Верно:
curl -X GET 'https://school.example.com/api/v1/orders?paid_at%5Bgte%5D=2026-07-01T00:00:00%2B03:00' \
-H 'Authorization: Bearer lms_live_a8f3c1e9d2b74a5f8e0c1d3b5a7f9e2c' \
-H 'Accept: application/json'
Любая HTTP-библиотека кодирует это сама, если передавать параметры параметрами, а не склеенной строкой.
Второй заказ после таймаута #
Отправили создание заказа, получили таймаут, повторили — заказов два.
Сеть теряет ответы, а не запросы: первый запрос мог выполниться. Повтор
операции записи всегда идёт с тем же Idempotency-Key — тогда повторять можно
сколько угодно. Идемпотентность.
409 на повторе, который «должен был» пройти #
Тот же Idempotency-Key пришёл с другим телом. Это ошибка клиента, и почти
всегда — баг генерации ключей: например, ключ считается от времени с точностью
до секунды, и две разные операции в одну секунду получают один ключ. Ключ должен
быть уникален для операции, одинаков для её повторов.
429 не проходит никогда #
Retry-After игнорируется, повтор в цикле. Ждите столько, сколько сказано
в заголовке, — он в секундах.
После 429 обход списка начат заново. Повторяйте тот же запрос с тем же курсором — иначе обход возвращается на первую страницу и не заканчивается никогда.
Значения «не сохраняются» или сохраняются странно #
- Булевы строками:
"true"— это неtrue. Булевы — булевы. - Деньги дробью:
1490.00— неверно. Целое в копейках, парой с валютой:{ "amount": 149000, "currency": "RUB" }. - Дата без пояса:
2026-08-09 14:30требует догадки о том, чей это пояс, и догадка будет неверной. Всегда ISO 8601 с поясом.
Полные правила — Формат.
Вебхук не проходит проверку подписи #
Подпись считается по разобранному телу. Большинство фреймворков разбирают JSON автоматически; собрав его обратно, вы получите другие байты и другую подпись. Подпись проверяется по сырому телу до разбора — на маршруте вебхука авторазбор надо отключить.
Часы сервера уехали. Метка времени в подписи проверяется с допуском 300 секунд. Расхождение больше — все подписи «неверны». Проверьте синхронизацию времени на приёмнике.
Вебхук приходит дважды #
Так и должно быть: доставка — «как минимум один раз». Повтор, переигрывание,
таймаут после успешной обработки — событие может прийти повторно, и обработчик
обязан быть идемпотентным по event.id. Как — с уникальным индексом, а не
проверкой перед вставкой: Вебхуки.
Вебхуки «через раз» и с повторами #
Обработчик работает синхронно и не укладывается в 10 секунд. Правильный
обработчик отвечает 200 сразу, а работает потом — иначе каждое событие
приходит по шесть раз, и все шесть обрабатываются.
Если ничего из списка не подошло #
В каждом ответе есть X-Request-Id. Запишите его, время и что делали — по нему
в журнале находится полная трассировка запроса. Это превращает разбор из гадания
в работу.