Документация LMS версия 0.1.0

Документация/API/Ошибки первого дня

Раздел описывает первый рабочий срез API. Срез в разработке: маршрутов ещё нет, экран ключей появится вместе с ним — до выкатки проверить запросы не обо что.

Ошибки первого дня

Всё из этого списка случается почти с каждым, обычно в первые сутки. Формат одинаковый: симптом → причина → починка. Ошибки идут от частых к коварным.

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. Запишите его, время и что делали — по нему в журнале находится полная трассировка запроса. Это превращает разбор из гадания в работу.

Эта страница в Markdown