← Все статьи

SiteGuard12 мин чтения

Оплата прошла, а заказ не оплачен: как сверить статус сайта и платёжного сервиса

Если оплата прошла, а заказ не оплачен на сайте, сначала сверьте конкретный платёж с конкретным заказом. Повторное списание не исправляет потерянную связь между ними. Покупателю нужно сохранить сведения об операции и обратиться в магазин; магазину — получить актуальный статус у платёжного сервиса, проверить сумму и найти этап, на котором результат перестал отражаться в учёте. Ниже разобран такой порядок для интеграции с ЮKassa.

1. Что сохранить покупателю, если сайт не видит оплату

Сохраните номер заказа, дату и время попытки, сумму, название магазина и доступный идентификатор операции. Если есть письмо или чек, приложите его к обращению в поддержку магазина. Опишите отдельно два наблюдения: что показывает банк или платёжная форма и что написано в личном кабинете сайта. Так поддержка сможет проверить нужную попытку, а не соседний заказ с похожей стоимостью.

Не нажимайте «Оплатить» ещё раз только для проверки. Не создавайте новый заказ, пока магазин не выяснит судьбу предыдущей операции. Скриншот полезен для поиска, но не заменяет серверную сверку: на нём может отображаться резервирование суммы, другая попытка или состояние на более ранний момент.

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

2. Соберите карточку заказа и всех попыток оплаты

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

Поле сверкиЧто зафиксировать
ЗаказВнутренний ID, версия состава, ожидаемая сумма и валюта
Платёжpayment_id каждой попытки, время создания, текущий статус
КонтекстМагазин ЮKassa, получатель, тестовая или рабочая операция
Учёт сайтаУчтённая сумма, запись о применении результата, связанные возвраты

Проверьте контекст до изменения статусов. Успешный платёж другого магазина или тестовая операция не подтверждают оплату рабочего заказа. Поля id, recipient, test, amount и metadata представлены в объекте платежа ЮKassa. Сопоставляйте их с серверными данными магазина. Номер заказа из адресной строки покупателя нельзя считать достаточным основанием для привязки чужого платежа.

Если payment_id не сохранился рядом с заказом, восстановите связь по серверному журналу создания и ответу провайдера. Совпадение суммы и близкого времени помогает найти кандидата, но не доказывает принадлежность: несколько покупателей могут одновременно платить одинаковую стоимость. До подтверждения связи оставьте операцию на ручной проверке. Не прикрепляйте первый найденный успешный платёж к заказу только ради исчезновения предупреждения.

3. Различайте четыре статуса платежа

Фраза «в ЮKassa статус платежа не меняется» требует уточнения: какой объект проверяют и в каком состоянии он находится. В описании процесса платежа выделены следующие статусы:

СтатусСмысл для сверки
pendingПлатёж ещё не завершён; необходимо дождаться определённого результата
waiting_for_captureДеньги авторизованы, но ожидают списания магазином
succeededПлатёж успешно завершён; статус конкретного платежа финальный
canceledПлатёж отменён; статус конкретного платежа финальный

pending не всегда означает, что покупатель ничего не сделал. Документация описывает случаи ожидания после пользовательского подтверждения, например в отдельных сценариях с чеками или периодом охлаждения. Не переводите такой платёж в «успешный» по одному времени ожидания.

Локальный статус заказа имеет другой смысл. Заказ может быть частично оплачен, отменён покупателем, передан в сборку или возвращён. Не пытайтесь разместить все эти состояния в одном поле с четырьмя значениями провайдера. Сохраняйте состояние платежа отдельно и вычисляйте состояние заказа по правилам магазина, учитывая все связанные операции.

4. Почему paid=true ещё не означает завершённое списание

Особенно опасна проверка только булевого поля paid. В официальном примере ЮKassa платёж waiting_for_capture имеет paid=true. Следовательно, такой признак не равнозначен status=succeeded. В двухстадийном сценарии он может сопровождать уже авторизованную сумму, которая ещё ожидает capture.

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

Если обнаружен waiting_for_capture, проверьте, предусмотрен ли двухстадийный сценарий настройками интеграции и кто принимает решение о списании. Посмотрите expires_at конкретного платежа: универсального срока capture для всех способов оплаты нет. Подтверждение или отмена — самостоятельные операции по правилам магазина. Не выполняйте их как диагностический эксперимент и не запускайте capture автоматически для всех найденных резервирований.

Для сверки запишите результат точно: «авторизовано», «успешно списано» или «отменено». Слова «деньги есть» недостаточно: разные сотрудники могут понимать под ними разные этапы и принять противоположные решения по одному заказу.

5. Получите актуальное состояние через API

Разработчик магазина проверяет платёж серверным запросом чтения по сохранённому payment_id. Схема запроса, без данных аутентификации:

GET https://api.yookassa.ru/v3/payments/{payment_id}

Метод получения информации и его отличие от подтверждения или отмены описаны в документации журналов ЮKassa. Для диагностики нужен именно просмотр текущего объекта. Используйте штатную серверную интеграцию; секретный ключ нельзя переносить в браузер покупателя или публиковать в переписке.

Сохраните время чтения, HTTP-код, полученный status, идентификатор, сумму, валюту и контекст магазина. Согласно правилам обработки ответов, HTTP-код нужно рассматривать вместе со статусом объекта. HTTP 200 с pending не означает, что платёж завершён. Ошибка или таймаут запроса чтения также не превращают ранее неизвестный платёж в отменённый.

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

Когда запрос не позволяет получить объект, сначала проверьте сохранённый ID, выбранный магазин и используемые сервером настройки. Не делайте вывод «покупатель не заплатил» из ошибки доступа вашей интеграции. Если данные противоречат друг другу, передайте поддержке провайдера идентификатор, время и обезличенный технический результат. Разделите проблему чтения сведений и проблему самого платежа, чтобы исправление доступа не превратилось в повторную финансовую операцию.

6. Отделите возврат покупателя от подтверждения платежа

Переход на return_url означает возвращение браузера на сайт. В сценарии Redirect ЮKassa использует этот адрес и при успешном исходе, и когда что-то пошло не так. Поэтому страница «Спасибо» сама по себе не подтверждает платёж. Счётчик аналитики на этой странице тоже измеряет посещение, а не завершённое списание.

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

Отделите проблему отображения от проблемы учёта. В базе оплата может быть уже применена, а кабинет показывать старые данные из кеша. Или интерфейс отображает успех, хотя запись оплаты не сохранилась. Попросите разработчика показать оба свидетельства: актуальную серверную запись заказа и ответ интерфейса, который видит покупатель. Один скриншот здесь не устанавливает, какой слой расходится с провайдером.

7. Сверьте сумму, валюту и назначение каждой попытки

status=succeeded подтверждает результат конкретного платежа, но не автоматически полную оплату любого связанного заказа. Сравните сумму с зафиксированной стоимостью нужной версии заказа, включая согласованные скидки и доставку. Если корзину изменили после создания платежа, сначала выясните, какая стоимость была предъявлена покупателю. Не подгоняйте задним числом ожидаемую сумму под найденную операцию.

Суммы сопоставляйте в одной валюте и с точным представлением денежных значений. Для рублей удобно сверять целые копейки либо использовать десятичный денежный тип. Не округляйте расхождение до «примерно той же суммы». Комиссию и перечисление магазину учитывайте отдельно от суммы, которую внесли в оплату заказа: это разные величины.

Для частичной оплаты нужен явный учёт частей. В учебном заказе на 7500 рублей внесён успешный аванс 3000 рублей, а оставшиеся 4500 находятся в waiting_for_capture. Успешно завершённая оплата пока составляет 3000, не 7500. После подтверждённого успешного завершения второй части получается 3000 + 4500 = 7500. Это модель аванса и доплаты магазина, а не название отдельного способа оплаты ЮKassa.

Частичное списание одного резервирования также проверяйте по фактически подтверждённой сумме. Первоначально запрошенная сумма не должна автоматически попадать в учёт как полностью принятая, если магазин подтвердил только её часть.

8. Разберите расхождение на учебном примере

Условный заказ A-742 стоит 4800 рублей. Ниже три попытки оплаты одного заказа в одном рабочем магазине; P1–P3 — сокращённые обозначения, не настоящие payment_id. Все состояния получены актуальным чтением, сумма каждой попытки равна 4800 RUB.

ПопыткаСтатус провайдераЧто обнаружено на сайте
P1canceledСтарая отменённая попытка сохранена в истории
P2succeededСвязь с A-742 есть, но результат не применён к заказу
P3pendingПоле «последняя попытка» указывает сюда; кабинет пишет «Не оплачен»

Суммировать 4800 × 3 нельзя: созданные попытки не равны принятым оплатам. Для этого снимка успешно завершён один платёж на 4800 рублей. Следующий шаг — выяснить, почему P2 не учтён, и восстановить его применение к A-742 после проверки возвратов и остальных условий заказа.

Незавершённую P3 продолжайте контролировать по предусмотренному сценарию. Если она тоже перейдёт в succeeded, сохраните её как отдельный успешный платёж и направьте возможную переплату на разбор; повторную отгрузку это запускать не должно. Повторное уведомление о P2, напротив, не создаёт новую оплату. Не считайте P3 отменённой только потому, что уже нашли P2. Пользователю не предлагают продолжать эту попытку, пока магазин разбирает ситуацию.

Если позднее приходит старое сообщение о P1, оно относится к P1. Оно не должно отменять успешный P2 и возвращать оплаченный заказ в исходное состояние. Ошибка здесь находится в сопоставлении операций, даже если каждое уведомление доставлено исправно.

9. Проследите путь от события до записи в заказе

Webhook сообщает об изменении объекта, но получение HTTP-запроса сайтом — только один этап. Проверьте последовательность: событие принято и проверено, найден нужный платёж, установлена связь с заказом, применена сумма, сохранена запись, обновлён пользовательский результат. Ищите первый отсутствующий этап вместо предположения «уведомления не работают».

По документации ЮKassa объект в уведомлении отражает состояние на момент события. При расхождении сверяйтесь с актуальным чтением API. Не позволяйте более старым данным откатывать уже подтверждённое терминальное состояние конкретного платежа. Сравнение только времени поступления сообщений не устанавливает порядок реальных переходов.

Если событие принято, а запись заказа не изменилась, проверьте локальную ошибку: не найден внутренний ID, сработало неверное условие суммы, откатилась транзакция базы или завершилась с ошибкой задача применения результата. Сохраните идентификатор и итог именно этой задачи. Настройка повторной доставки webhook не исправит неверную связь платежа с заказом.

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

10. Учитывайте возвраты отдельно от статуса платежа

Успешный платёж может сопровождаться последующим возвратом. Это не переход payment.status из succeeded в canceled. У возврата ЮKassa собственный объект, идентификатор, сумма, статус и ссылка payment_id на исходную операцию. Сверять нужно обе записи.

Продолжим учебный пример: P2 успешно завершён на 4800 рублей, затем подтверждён успешный частичный возврат 1200 рублей. Получено по платежу 4800, возвращено 1200, разница составляет 3600 рублей. Это техническая сверка сумм операций, а не автоматический расчёт долга покупателя. Заказ мог быть изменён или частично отменён, поэтому сумма обязательств определяется отдельно правилами учёта магазина.

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

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

11. Исправляйте локальный учёт без нового списания

Когда текущий объект проверен, определите конкретную причину: неправильная связь, пропущенное применение результата, ожидание capture, несовпадение суммы или устаревшее отображение. Для каждой причины нужен свой шаг. Кнопка «Принудительно оплатить заказ» без записи основания скрывает проблему и может запустить ненужные действия склада или CRM.

Перед локальным восстановлением сохраните состояние заказа и перечень связанных операций. Укажите, какой платёж и на какую сумму будет учтён, почему он относится именно к этому заказу, проверены ли возвраты и есть ли другие незавершённые попытки. Проверьте, не отменён ли сам заказ и допустим ли дальнейший запуск исполнения. Успешное получение денег не отменяет бизнес-решение об отмене покупки.

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

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

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

12. Проверьте исправление и контроль расхождений

Воспроизводите дефект на тестовых заказах. Тестовый магазин ЮKassa позволяет проверять поддерживаемые сценарии без реального списания; тестовые операции нельзя использовать как оплату рабочих заказов. Настройки, ключи и маршруты тестовой среды должны быть явно отделены от рабочих.

  • Успешный платёж нужного магазина учитывается в правильном заказе на правильную сумму.
  • waiting_for_capture с paid=true не выдаётся за завершённое списание.
  • Закрытие вкладки и повторное открытие return_url не меняют подтверждённый финансовый результат.
  • Несколько попыток не скрывают успешную оплату; старое событие не отменяет её учёт.
  • Частичная оплата и успешный возврат сохраняются отдельными записями.
  • Повторная сверка не создаёт новую оплату, вторую отгрузку или повторную выдачу доступа.

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

Следить за HTTP-доступностью сайта извне можно с SiteGuard. Сверку платежей, сумм и состояния заказа выполняет ваша интеграция: доступность сайта сама по себе не подтверждает корректность финансового учёта.