API вернул ошибку, и рука тянется к кнопке «Повторить». Стоп. При `401` повтор не вернёт доступ. При `429` он сильнее упрётся в лимит. После `500` он иногда создаст второй заказ, счёт или платёж. Один код — разные действия.

За 30 секунд: куда смотреть
| Код | Что произошло | Первое действие |
|---|---|---|
| `401` | API не подтвердило авторизацию | Проверить токен и заголовок `Authorization` |
| `429` | Превышен лимит запросов | Найти `Retry-After` и остановить поток |
| `500` | Сервер столкнулся с внутренней ошибкой | Проверить, выполнилась ли операция |
HTTP-код не ставит точный диагноз. Он показывает, где искать проблему. Для каждого сбоя сохраните время запроса, URL, HTTP-метод, код ответа, тело ответа без секретов и ID операции в вашей системе. Эта мелочь потом экономит час переписки.
`401`: токен есть, но API вас не узнало
`401 Unauthorized` обычно не означает «вам запрещено». Чаще сервис не смог подтвердить, кто отправил запрос: данные авторизации не дошли, устарели или не подошли. Смотрите не только на код в репозитории, а на запрос, который реально ушёл из приложения.
Проверьте, есть ли `Authorization`, какая выбрана схема и не истёк ли токен. Часто нужен формат `Bearer <токен>`, но конкретный API может требовать другой. Затем проверьте окружение: ключ от тестового API нередко не работает в боевом, а после деплоя секрет может просто исчезнуть из переменных.
Ночная выгрузка заказов в CRM утром начала возвращать `401`. Команда уже хочет пересоздать ключи. В логах видно: заголовок есть, но длина токена равна нулю. После деплоя пропала переменная `CRM_API_TOKEN`. Вернули секрет, перезапустили сервис — выгрузка заработала.
Не пишите токен в логи. Достаточно сохранить факт наличия заголовка, схему авторизации, длину значения и имя окружения. Иначе обычная ошибка доступа превратится в утечку ключа. Вери-вери плохой размен.
Если сервис понял, кто вы, но запретил конкретное действие, он чаще вернёт `403 Forbidden`. Разницу между `401`, `403`, правилами методов и ответом `500` фиксирует стандарт HTTP.
`429`: лимит не лечится новыми запросами
`429 Too Many Requests` означает, что API временно ограничило поток запросов. Лимит могут считать по токену, IP-адресу, аккаунту, пользователю или отдельному методу. Сам код не объясняет, какой именно порог вы задели.
Сначала посмотрите заголовок `Retry-After`. В нём бывает число секунд или точное время, до которого нужно ждать. Если заголовок есть, не гадайте: поставьте исходную задачу в очередь до указанного момента.
Если `Retry-After` нет, остановите запуск новых одинаковых задач. Уменьшите число параллельных запросов и увеличивайте паузу между попытками. Добавьте случайный разброс: иначе десятки воркеров подождут одинаковое время и дружно придут в API снова.
Остановить запуск новых одинаковых задач
Поставить неотправленные задачи в очередь
Уменьшить число параллельных запросов
Повторять только безопасные операции
Для операций создания использовать идемпотентность, если API её поддерживает
Увеличивать паузу между попытками и добавлять случайный разброс
Ограничить число попыток и общее время ожидания
Повторять исходную задачу с тем же ID, а не создавать новуюИнтернет-магазин после большого импорта проверяет статус каждой доставки. В спокойный день всё работает, после загрузки появляется `429`. Здесь не помогут «ещё три ретрая». Ограничьте параллельность и отправляйте проверки через очередь. API перестанет захлёбываться, а одна доставка не получит пять одинаковых запросов.

Нужно понять, в каком формате API может прислать `Retry-After`? В RFC 6585 есть определение `429` и этого заголовка. Пять минут первичного источника тут полезнее курса «ретраи для начинающих».
`500`: сервер упал, но операция могла пройти
`500 Internal Server Error` значит только одно: сервер, который отдал ответ, столкнулся с неожиданной проблемой. Это не доказывает, что сломался внешний провайдер. Ошибка может жить в вашем бэкенде, прокси, API-шлюзе или функции между вами и сервисом.
Не отправляйте в поддержку сообщение «у вас 500, чините». Соберите URL и метод, точное время с часовым поясом, код и тело ответа, заголовки ответа, ID запроса от API и ID операции у вас. Названия идентификаторов отличаются: это могут быть `request-id`, `x-request-id`, `trace-id` или что-то своё.
Сервис отправил `POST` на создание счёта и получил `500`. Автоматический повтор способен создать второй счёт: первый запрос мог сохраниться до сбоя, а ответ потеряться по дороге. Сначала найдите счёт по внешнему ID операции. Если API поддерживает ключ идемпотентности, повторяйте запрос с тем же ключом. Новый ключ создаст новую операцию.
Не прикладывайте к тикету токены, пароли, платёжные и персональные данные. Поддержке нужен след запроса, а не скриншот с секретами из общего чата.
Безопасный запрос — не всегда идемпотентный
Эти слова часто смешивают. `GET` и `HEAD` — безопасные методы: они не должны менять состояние системы. `PUT` и `DELETE` не считаются безопасными, но являются идемпотентными: повтор одинакового запроса не должен менять конечный результат.
Обычный `POST` часто неидемпотентен. Два одинаковых запроса способны создать два заказа, две заявки или два списания. Но метод сам по себе не решает всё: конкретное API может сделать `POST` идемпотентным через специальный ключ или внешний ID.
После сетевого сбоя не считайте операцию неуспешной только потому, что не получили ответ. Сервер мог выполнить действие, а соединение оборвалось позже. Для платежей, заказов и создания сущностей сначала проверяйте факт выполнения — потом решайте, нужен ли повтор.
Шаблон для поддержки без трёх кругов переписки
Добавьте этот шаблон в README интеграции и карточку инцидента. Он пригодится дежурному разработчику и человеку, который пишет в поддержку.
Ошибка: 401 / 429 / 500
Время: YYYY-MM-DD HH:MM:SS UTC
Метод и URL: POST /v1/orders
ID операции в нашей системе: order_...
ID запроса от API: ...
Тело ответа: без токенов, паролей и персональных данных
Что уже проверили: токен / Retry-After / очередь / факт выполнения операцииПри `401` проверьте реальный `Authorization`. При `429` остановите поток и включите очередь. При `500` найдите след операции до повтора `POST`. Сегодня добавьте в логи ID операции рядом с ID запроса: в следующий сбой вы не будете гадать, создался ли счёт, а просто это проверите.
Статья помогла?


