API и надёжная интеграция

Коды ошибок платёжного API: как их обрабатывать

Код ошибки платёжного API — это инструкция для вашего сервера, а не текст для покупателя. Разбираем три группы ошибок и как их обрабатывать без лишних тикетов.

Коротко: как читать коды ошибок платёжного API

Коды ошибок обычно делятся на три группы: ошибка в запросе от вашего сервера, отказ на стороне провайдера или банка и временный сбой инфраструктуры. Каждая группа требует разной реакции — от немедленного лога и остановки интеграции до автоматического повтора запроса через несколько секунд.

Почему нельзя показывать сырой код ошибки покупателю

Технический код вроде invalid_signature или provider_timeout ничего не говорит человеку на странице оплаты — он просто уйдёт, решив, что сервис не работает. Ошибку нужно переводить в понятный текст на вашей стороне: «повторите попытку через минуту» или «выберите другой способ оплаты» — а исходный код оставлять в логах для разбора.

Три группы ошибок и что с ними делать

  • Ошибки запроса. Неверная подпись, отсутствующее обязательное поле, некорректная сумма. Это ваша ошибка интеграции — исправляется на стороне кода, а не повтором запроса.
  • Отказ провайдера или банка. Недостаточно средств, превышен лимит, банк заблокировал операцию. Повторять тот же запрос бессмысленно — нужно показать причину покупателю и предложить другой способ оплаты.
  • Временный сбой. Таймаут, недоступность провайдера, сетевая ошибка. Здесь уместен автоматический повтор с задержкой — но с ограничением по числу попыток, чтобы не заспамить провайдера одним и тем же запросом.

Как коды ошибок связаны с идемпотентностью

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

Мониторинг кодов ошибок как метрика

Отдельная польза от структурированных кодов — возможность считать их долю от общего числа запросов и настраивать алерт на резкий рост конкретной категории. Всплеск ошибок подписи почти всегда означает баг в свежем деплое на вашей стороне, а всплеск таймаутов провайдера — проблему уже не у вас, а на стороне инфраструктуры. Без разбивки по кодам оба случая выглядят одинаково — просто «выросло число ошибок оплаты», и разбираться приходится вслепую.

Частые ошибки обработки

  • Одна и та же реакция на все коды. Ошибка подписи и таймаут провайдера требуют разных действий — нельзя просто показывать общий текст «что-то пошло не так» на оба случая.
  • Бесконечные повторы без ограничения. Автоматический ретрай без лимита попыток и задержки может создать нагрузку на провайдера и заблокировать вашу интеграцию за спам-паттерн.
  • Нет логирования исходного кода ошибки. Если сохраняется только «оплата не прошла», через месяц невозможно понять, сколько ошибок было техническими, а сколько — отказами банка.
  • Игнорирование кода в пользу общего HTTP-статуса. 400 или 500 сам по себе не объясняет причину — смысл несёт код ошибки в теле ответа.

Как это устроено в RollyPay

API возвращает структурированный код ошибки и человекочитаемое описание в одном ответе — можно логировать код для разбора и сразу показывать покупателю понятный текст, не переводя техническую формулировку вручную. Идемпотентный ключ поддерживается на создание платежа, поэтому повтор запроса после таймаута безопасен и не создаёт задвоенный платёж. Документация перечисляет коды по категориям, чтобы при интеграции можно было сразу заложить нужную реакцию на каждую группу, а не дорабатывать обработку ошибок постфактум.

Пример: интеграция без разбора кодов ошибок

Команда подключила API и обрабатывала любую неудачу одинаково: показывала покупателю текст «оплата не прошла, попробуйте позже» и логировала только факт ошибки без кода. Через месяц в поддержку начали поступать жалобы на платежи, которые «зависли» — на деле это были обычные таймауты провайдера, которые сервер даже не пытался повторить. Разбор логов занял два дня именно потому, что в них не было исходного кода ошибки — только общая пометка «ошибка оплаты».

После разделения ошибок на три группы и добавления повтора с идемпотентным ключом для временных сбоев доля обращений в поддержку по теме «платёж завис» заметно снизилась — большая часть таких случаев стала решаться автоматическим повтором ещё до того, как покупатель успевал написать в чат.

Что проверить в обработке ошибок

  • Каждая группа ошибок — запрос, отказ, сбой — обрабатывается своей логикой, а не одним общим catch.
  • Исходный код ошибки сохраняется в логах, а не только факт неудачи.
  • Повтор запроса идёт с идемпотентным ключом и ограничением по числу попыток.
  • Текст на странице оплаты понятен покупателю без знания внутренних кодов API.

Частые вопросы

Можно ли показывать код ошибки API прямо покупателю?

Не стоит — технический код вроде invalid_signature или provider_timeout ничего не говорит человеку. Переведите его в понятный текст на своей стороне, а исходный код сохраните в логах.

Всегда ли стоит повторять запрос после ошибки?

Нет. Повтор имеет смысл только для временных сбоев — таймаутов и недоступности провайдера. Ошибку запроса или отказ банка повтором не исправить.

Как избежать дублирования платежа при повторном запросе?

Использовать идемпотентный ключ на каждый запрос создания платежа — повтор с тем же ключом вернёт результат первой попытки вместо создания второй операции.

Что важнее — HTTP-статус ответа или код ошибки в теле?

Код ошибки в теле ответа. HTTP-статус вроде 400 или 500 сам по себе не объясняет причину — конкретную логику обработки нужно строить на структурированном коде.

Источники и документация