Правильный жизненный цикл платежа
- сайт создаёт локальный заказ;
- сервер создаёт платёж у провайдера;
- сохраняет payment_id;
- отправляет пользователя на подтверждение;
- принимает webhook;
- проверяет статус платежа;
- только после подтверждённого статуса помечает заказ оплаченным.
Что нельзя считать подтверждением оплаты
| Событие | Достаточно? |
|---|---|
| Пользователь открыл return_url | нет |
| JS показал success | нет |
| Webhook пришёл один раз | нужно проверить подлинность/статус |
| API вернул succeeded/финальный статус | да, согласно модели провайдера |
| Локальный order status изменился вручную | нет |
Пример создания платежа с ключом идемпотентности
$idempotencyKey = bin2hex(random_bytes(16));
$payload = [
'amount' => ['value' => '100.00', 'currency' => 'RUB'],
'capture' => true,
'confirmation' => [
'type' => 'redirect',
'return_url' => 'https://example.com/order/123/return',
],
'description' => 'Заказ #123',
];
// Отправляйте запрос С СЕРВЕРА.
// Ключ идемпотентности сохраняйте вместе с попыткой операции.Повторный POST должен быть безопасным
При сетевой ошибке клиент может не знать, создался платёж или нет. Поэтому платёжные API используют идемпотентность: повтор той же операции с тем же ключом не должен создавать вторую транзакцию.
Webhook должен переживать повторы
Платёжный провайдер может доставлять уведомление несколько раз. Сохраняйте event/payment id и обновляйте заказ идемпотентно.
Что тестировать до запуска
| Сценарий | Проверка |
|---|---|
| Успешная оплата | заказ paid один раз |
| Пользователь закрыл оплату | заказ не становится paid |
| Webhook пришёл дважды | нет дубля операции |
| Timeout API | безопасный повтор |
| Возврат | |
| ронизирован | |
| Неверная сумма/status | заказ не подтверждён автоматически |
Return URL и webhook решают разные задачи
Return URL нужен для интерфейса пользователя. Webhook/API — для серверной фиксации результата. Не связывайте бухгалтерский статус заказа только с браузерным переходом.
Связанные материалы
Сценарии проверки подключения онлайн-оплаты
Тестируйте полный цикл: создание платежа, успешное подтверждение, отказ, обрыв связи, позднее уведомление, повторный webhook и возврат. Изменять статус заказа следует только по проверенному серверному событию, а не по одному открытию страницы «Спасибо». Платёжный идентификатор, сумма и валюта должны сверяться с данными заказа.
При интеграции цифровой выдачи дополнительно убедитесь, что повторное уведомление не отправляет ключ или доступ несколько раз. Сохраняйте понятный журнал событий без платёжных секретов и лишних персональных данных.