Интеграция платежного шлюза в Азербайджане — это не только подключение страницы checkout. После запуска возникнут реальные операционные ситуации: клиент пройдет 3D Secure, но не вернется в браузер; уведомление от провайдера придет с задержкой; один webhook будет доставлен повторно; возврат будет принят в обработку, но позже отклонен платежной системой. Архитектура должна давать однозначный ответ, что произошло с заказом и деньгами.
Правильный подход — считать провайдера внешней системой обработки платежа, а ваше приложение — системой принятия бизнес-решений по заказу, доступу к услуге и возвратам. Между ними нужны устойчивые идентификаторы, проверяемые события, строгие переходы статусов и регулярная сверка. Именно это отличает рабочую online payment gateway integration от простой кнопки «Оплатить».
Сначала модель заказа и попытки оплаты
Создавайте внутренний заказ до переадресации пользователя на оплату. Каждое открытие платежной сессии должно создавать отдельную попытку оплаты. Один заказ может иметь несколько попыток: первая карта отклонена, пользователь закрыл страницу аутентификации или повторил оплату другим способом.
- Присвойте заказу неизменяемый внутренний ID.
- Для каждой попытки создавайте свой ID и merchant reference, передаваемый провайдеру.
- Храните сумму в минимальных денежных единицах целым числом и отдельно код валюты; не используйте float.
- Сохраняйте ID операции провайдера, релевантные коды ответа, время и ссылки на входящие события.
- Не смешивайте авторизацию, подтверждение оплаты, возврат и фактическое зачисление по settlement.
Не распространяйте статусы конкретного провайдера по всей системе. Введите небольшой внутренний автомат состояний, например: created → checkout_started → pending_authentication → authorised/captured → paid. Для альтернативных исходов предусмотрите failed, cancelled, expired и unknown. Для каждого перехода заранее определите источник, разрешение и действие. Позднее сообщение об ошибке не должно автоматически отменять уже подтвержденный paid-статус: такое расхождение должно попадать в очередь исключений.
Webhook — источник подтверждения, а не return URL
Страница, на которую пользователь вернулся после оплаты, не является доказательством результата. Пользователь мог потерять соединение, закрыть вкладку или вернуться до завершения обработки у провайдера. Финальный статус заказа должен устанавливаться после проверки подписанного server-to-server webhook, либо после документированной проверки статуса через API, если webhook недоступен.
Как обрабатывать webhook надежно
- Проверяйте подлинность. Валидируйте подпись, HMAC или иной механизм провайдера на исходном теле запроса. Невалидное событие не должно менять данные.
- Сначала сохраняйте. Фиксируйте event ID, необходимые заголовки, payload или его защищенную ссылку, время получения и итог обработки. Не записывайте в логи карточные данные и секреты.
- Отвечайте быстро. После проверки и надежного сохранения возвращайте 2xx; отправку писем, выдачу доступа и тяжелую бизнес-логику выполняйте асинхронно.
- Обеспечьте идемпотентность. Повтор webhook не должен повторно выдать доступ, создать второй чек или запустить второй возврат.
- Храните основание перехода. Сотрудник должен видеть, какое событие или ответ API изменило статус попытки.
Идемпотентность нужна и для исходящих запросов. Для создания платежа, capture, отмены и refund используйте уникальный ключ идемпотентности и храните его. Если сервис получил timeout уже после отправки запроса, повтор не должен создавать второй платеж или дублирующий возврат.
Не оставляйте pending и неуспешные платежи без процесса
Сообщение «Оплата не прошла» полезно покупателю, но недостаточно для команды. В административной части должны быть видны ID заказа, история попыток, ссылка провайдера, сумма, валюта, последний подтвержденный статус, допустимая причина отказа и время обновления. Клиенту покажите понятный следующий шаг: повторить попытку, выбрать другой способ или обратиться в поддержку, не раскрывая служебные коды.
Для попыток, слишком долго остающихся в pending, создайте плановую задачу восстановления. Она выбирает только подходящие незавершенные попытки, запрашивает статус у провайдера, применяет те же правила перехода и журналирует результат. Не исправляйте платежи прямым изменением строк в базе. Ручное решение должно быть отдельным действием с правами, причиной и неизменяемой записью аудита. Такие возможности должны быть частью веб-платформы или приложения, а не таблицы, которую команда ведет после запуска.
Возврат — контролируемый процесс, а не одна кнопка
Первичный ответ API о refund может означать только принятие запроса. Далее возможны асинхронная обработка, отказ и, в зависимости от метода оплаты, иные последующие изменения. Поэтому возврат нужно хранить отдельной сущностью, связанной с исходной успешной попыткой платежа.
- Разрешайте возврат только для операций, подходящих по статусу и правилам провайдера.
- Считайте доступную к возврату сумму из завершенных и ожидающих возвратов; не допускайте ручного превышения.
- Разделяйте статусы requested, pending, refunded и refund_failed.
- Ограничьте инициирование ролями; для чувствительных операций добавьте второе согласование.
- Сохраняйте ключ идемпотентности и ID возврата у провайдера.
- Подтверждайте итог через webhook или проверку статуса, а не только ответ на первоначальный запрос.
Пользователю следует показывать честный статус: «запрос на возврат создан» или «возврат обработан», а не обещать дату поступления, которой вы не управляете. В админ-панели должны быть причина, инициатор, согласующий, ссылка на исходную операцию и история событий. Для финансово сложных продуктов такие процессы можно проектировать в рамках FinTech и trading-систем.
Сверка: связь между paid, settlement и деньгами на счете
Успешная оплата, зачисление в settlement, комиссия, возврат и спорная операция происходят не обязательно одновременно. Сверка сопоставляет внутренние payment attempt и refund с отчетами провайдера по операциям и выплатам, а затем — с данными учета или банка. Без нее в отчете «оплаченные заказы» могут скрываться пропущенные webhook, нераспознанные операции, задержанные выплаты и неверно учтенные комиссии.
Используйте для сопоставления merchant reference, ID транзакции провайдера, сумму, валюту, дату операции и reference выплаты/settlement. Разделяйте исключения по понятным причинам: операция провайдера отсутствует внутри системы, внутренняя paid-попытка не найдена у провайдера, не совпала сумма, ожидается settlement, не совпал возврат или повторно использован reference. Финансовой команде нужна очередь исключений с фильтрами, ответственным и комментариями. В этом практический смысл payment reconciliation software: не новый громкий термин, а контролируемый процесс поиска и устранения расхождений.
Безопасность и checklist перед релизом
По возможности используйте hosted payment page провайдера или корректно подключенный защищенный embedded-компонент, чтобы карточные данные не проходили через ваши серверы. Это уменьшает область риска, но не отменяет защиту сайта merchant. Рекомендации PCI SSC указывают, что даже при redirect и iframe важно контролировать риски на странице merchant, включая сторонние скрипты, способные повлиять на оплату. Уточните применимые к вашей реализации требования у acquiring bank и специалистов по соответствию.
- В sandbox проверьте успех, отказ, отмененную 3D Secure, отсутствие возврата браузера, задержанный и повторный webhook, а также временный ответ 5xx от endpoint.
- Разделите тестовые и production-учетные данные; храните секреты в безопасном механизме управления секретами.
- Настройте мониторинг ошибок доставки webhook, очереди задач, стареющих pending-платежей, неуспешных refund и исключений сверки.
- Протестируйте права на возвраты, журнал аудита и процесс ручного разбора вместе с будущими операторами.
- До подписания договора изучите отчеты settlement, комиссии, правила dispute, ограничения возвратов и порядок эскалации у выбранного провайдера.
В POLADO услуга Веб-платформы и приложения охватывает весь жизненный цикл платежа: UX checkout, модель статусов, webhook worker, административные операции и отчеты сверки. Если нужен единый опыт в приложении, его следует строить поверх того же backend через разработку мобильных приложений. Запланируйте техническую консультацию до запуска: разберем документацию провайдера, сценарии отказов и операционные механизмы, которые понадобятся команде с первого дня.