Статусы платежа
Статус — в поле status объекта платежа. Статусов три.
status | Что значит | Что делать магазину | Может измениться? |
|---|---|---|---|
pending | Платёж создан. Покупатель ещё не заплатил. | Ждать. Заказ не выполнять. Если покупатель хочет вернуться к оплате до expires_at, отправить его на тот же confirmation_url — только если сумма заказа не менялась. Если менялась — создать новый платёж с новым ключом идемпотентности. | Да: станет succeeded или canceled. |
succeeded | Покупатель заплатил. paid равно true. | Сверить amount с суммой заказа и выполнить заказ один раз. | Нет. Возврат денег статус не меняет. |
canceled | Платёж не оплачен: истёк срок, банк отказал или платёж остановила проверка. Причина — в cancellation_details. | Заказ не выполнять. Чтобы покупатель заплатил снова, создать новый платёж с новым ключом идемпотентности. Связь заказа с этим платежом не удалять. | Редко: может стать succeeded — см. поздняя оплата. |
Как меняется статус
pending ──► succeeded
│ ▲
│ │ поздняя оплата (редко)
└──────► canceled
- Новый платёж всегда в статусе
pending. - Из
pendingплатёж переходит вsucceededили вcanceled. succeeded— окончательный статус.canceledпочти всегда окончательный. Исключение — поздняя оплата.
Правила для кода
- Выполняйте заказ только при
status=succeeded. Не смотрите для этого наpaid,income_amountили факт возврата покупателя на сайт. - Перед выполнением заказа сверьте
amount.valueиamount.currencyс суммой заказа. Если сумма заказа изменилась после создания платежа (покупатель поменял корзину, открыл заказ в двух вкладках), создайте новый платёж с новым ключом идемпотентности. Платёж на старую сумму не засчитывайте; если его оплатят — верните деньги в личном кабинете. - Узнавайте статус запросом
GET /v3/payments/{payment_id}. Тело уведомления может быть устаревшим. - Выполняйте заказ ровно один раз. Отмечайте заказ оплаченным атомарно: условным
UPDATE(например,UPDATE orders SET paid_payment_id = … WHERE id = … AND paid_payment_id IS NULL) или с блокировкой строки. Уведомление и возврат покупателя наreturn_urlприходят одновременно: проверка «не выполнен — выполнить» без атомарности выполнит заказ дважды. - При
canceledне выполняйте заказ, но и не удаляйте связь заказа сidплатежа: платёж ещё может статьsucceeded. - Не полагайтесь только на уведомления: если ваш сервер был недоступен дольше 24 часов, они не придут. Раз в несколько минут сверяйтесь с API — как, написано в разделе Если уведомление не пришло.
- Незнакомый статус считайте как
pending: ждите и запросите платёж позже.
Поздняя оплата: canceled → succeeded
Иногда покупатель начинает оплату до expires_at, а банк подтверждает её позже. К этому моменту платёж уже canceled. Деньги покупателя пришли, поэтому платёж становится succeeded, и приходит уведомление payment.succeeded — даже если раньше приходило payment.canceled.
Что делать:
- выполните заказ, если он ещё актуален;
- если заказ уже не актуален (товар продан, покупатель создал новый платёж и оплатил его), верните деньги покупателю в личном кабинете.
Чтобы не пропустить позднюю оплату, обрабатывайте payment.succeeded для любого платежа заказа, даже отменённого, и не удаляйте связь заказа с id платежа. Сумму сверяйте так же: платёж на старую сумму заказа не засчитывайте, а деньги за него верните.
Поэтому canceled — не всегда окончательный статус. Не снимайте резерв товара и не удаляйте заказ только потому, что пришло payment.canceled, если не готовы вернуть деньги при поздней оплате.
Проверка оплаты в AvantPay
Иногда AvantPay проверяет оплату вручную. Деньги покупателя уже пришли, поэтому платёж — succeeded, paid равно true, приходит payment.succeeded. Пока идёт проверка, в объекте нет income_amount.
Выполняйте заказ как обычно — по статусу succeeded. Вопросы по такому платежу — в поддержку: [email protected], укажите id платежа.
Кто отменил платёж
У платежа со статусом canceled есть поле cancellation_details:
{
"party": "avantpay",
"reason": "expired_on_confirmation"
}
party — кто отменил:
party | Кто |
|---|---|
merchant | Магазин. Сейчас не встречается: отменить платёж через API нельзя. |
avantpay | AvantPay: истёк срок оплаты, платёж остановила проверка безопасности или его не удалось создать. |
payment_network | Банк покупателя, платёжная система или СБП. |
Не стройте логику заказа на party и reason: для решения достаточно status. Эти поля нужны, чтобы объяснить покупателю, что случилось.
Причины отмены
reason — почему отменён платёж. Что бы ни было в reason, заказ не выполняйте. Если покупатель хочет заплатить снова, создайте новый платёж с новым ключом идемпотентности.
reason | Кто ставит | Что случилось | Что сказать покупателю |
|---|---|---|---|
3d_secure_failed | payment_network | Покупатель не прошёл проверку 3-D Secure: ввёл неверный код или не дождался его. | Попробуйте оплатить ещё раз. Если не получится — обратитесь в свой банк. |
call_issuer | payment_network | Банк покупателя отказал без объяснения причины. | Обратитесь в свой банк или оплатите другим способом. |
canceled_by_merchant | merchant | Платёж отменил магазин. Сейчас не встречается. | — |
card_expired | payment_network | Истёк срок действия карты. | Оплатите другой картой или другим способом. |
country_forbidden | payment_network | Картой этой страны здесь заплатить нельзя. | Оплатите картой другого банка или другим способом. |
expired_on_confirmation | avantpay, payment_network | Покупатель не заплатил вовремя: прошёл expires_at или истёк срок QR-кода или ссылки у банка. | Время на оплату вышло. Начните оплату заново. |
fraud_suspected | avantpay, payment_network | Платёж остановлен из-за подозрения в мошенничестве. | Оплатите другим способом. |
general_decline | avantpay, payment_network | Причина не уточняется. | Попробуйте ещё раз или оплатите другим способом. |
insufficient_funds | payment_network | Не хватает денег на счёте покупателя. | Пополните счёт или оплатите другим способом. |
internal_timeout | payment_network | Банк или платёжная система не ответили вовремя. | Попробуйте оплатить ещё раз. |
invalid_card_number | payment_network | Неверный номер карты. | Проверьте номер карты и оплатите ещё раз. |
invalid_csc | payment_network | Неверный код CVV2/CVC2. | Проверьте код и оплатите ещё раз. |
issuer_unavailable | payment_network | Банк покупателя недоступен. | Попробуйте позже или оплатите другим способом. |
payment_method_limit_exceeded | payment_network | Исчерпан лимит платежей для способа оплаты или карты. | Попробуйте позже, на другую сумму или другим способом. |
payment_method_restricted | payment_network | Операции этим способом запрещены, например карта заблокирована. | Обратитесь в свой банк или оплатите другим способом. |
Если придёт значение, которого нет в таблице, обработайте его как general_decline.
Статусы в личном кабинете
В личном кабинете статусов больше. Вот как они соответствуют статусам API:
| В личном кабинете | status в API |
|---|---|
| Не оплачен, В обработке | pending |
| Оплачен, Возврат в обработке, Возвращён частично, Возвращён | succeeded |
| Ошибка оплаты, Просрочен, Отменён | canceled |