← Все уроки

УРОК 4 / 9

Создай оплату. Проверь платёж.

Создавай счета из своего бэкенда и обрабатывай проверенные уведомления оплаты.

Что получится

Серверный платёжный процесс с защитой от повторов и дубликатов.

1. Подготовь ID и доступ

Начни с активного магазина и проверенных способов оплаты. В Настройки → Доступ к APIсоздай ключ чтения/записи только для нужного проекта. Храни токен на бэкенде, никогда в браузерном коде или публичном репозитории.

Скопируй API ID проекта и API ID магазина из блока магазина Основное → API IDs . Это UUID, а не читаемый идентификатор проекта или номер заказа. Используй своё имя хоста API.

В разделе Магазин → IPN, создай секрет подписи до указания ipn_url. Твой HTTPS-обработчик должен быть доступен с VPS продавца.

2. Создай счёт

Замени значения-заглушки и отправь запрос с бэкенда. Суммы - десятичные строки, не вычисления с плавающей точкой.

curl --fail-with-body --request POST \
  'https://api.example.com/v1/projects/YOUR_PROJECT_ID/stores/YOUR_STORE_ID/invoices' \
  --header 'Authorization: Bearer YOUR_MERCHANT_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: order-1042-attempt-1' \
  --data '{
  "amount": "10.00",
  "currency": "EUR",
  "order_id": "order-1042",
  "description": "Example order",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  }
}'

Сохрани data.invoice_id с заказом, затем перенаправь клиента на links.checkout. Для новой попытки оплаты используй новый ключ идемпотентности. При тайм-ауте повторяй с теми же данными доступа, ключом и точными байтами тела.

Если не указывать payment_methods , используются способы магазина. Можно сузить их для счёта через slug сетей и тикеры; это никогда не включает непринимаемый актив. Все поля запроса и примеры ответов →

3. Выбери IPN, вебхуки или оба

IPN следует жизненному циклу счёта. Задай URL IPN магазина или переопредели через ipn_url для отдельного счёта. Вебхуки подписывают эндпоинт на выбранные события, например invoice.settled.

Формат подписи одинаковый, но секреты разные: IPN использует секрет IPN магазина, каждый вебхук - свой секрет. API Bearer-токен не используется для подписи ни в одном случае.

Если оба доставляются в приложение, ожидай пересекающиеся уведомления. Не начисляй оплату заказа дважды.

4. Проверь и сохрани уведомление

  1. Прочитай точное сырое тело до разбора JSON. Проверь Wholly-Signature со своим секретом, временем и защитой от повтора. Официальные SDK предоставляют проверку.
  2. Проверь проект, магазин, счёт и событие в подписанном теле. Неподписанные заголовки доставки не являются источником аутентификации.
  3. Надёжно сохрани событие с уникальным event_id, затем быстро верни HTTP 2xx. Обрабатывай заказы фоновой задачей.
  4. Запроси текущий счёт у настроенного API-хоста, не у произвольного хоста из запроса. Сверь сохранённые проект, магазин, сумму, валюту и номер заказа.

PHP · Python · JavaScript / TypeScript · Спецификация подписи и примеры обработчиков

5. Выполни заказ один раз после оплаты

Для событийного обработчика принимай event_type = invoice.settled, затем проверяй текущий status = settled и свою политику исключений. Выполняй заказ один раз в транзакции БД/с уникальным ограничением заказа.

Тип события и статус - разное

Быстро подтверждающая сеть может отправить оба payment.received и invoice.settled с status = settled. В другой сети payment.received ещё может содержать processing. Ни один вариант не является ошибкой.

Убирай дубликаты событий по event_id, не только sequence: разные типы событий могут иметь одну sequence. Обработчики SDK по состоянию вместо этого объединяют ревизии счёта и проверяют состояние независимо от типа события. Не совмещай такое объединение с фильтром типа события. Оба подхода требуют защиты от повторного выполнения заказа.

Проверь requires_review и ручные решения перед выполнением. amount_status = paid сам по себе не доказывает подтверждение. Верхнеуровневые поля оплаченного актива суммируют завершённую оплату; payment_info содержит подробные поступления и данные котировки. Все статусы, события и правила исключений →

6. Проверь повторы и восстановление

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

Проверь Магазин → IPN / Вебхуки → История → Подробностиили разделы доставки в деталях счёта. Повторная отправка использует записанное событие, не создаёт новое завершение оплаты.

Нехватка кредитов ставит IPN/вебхуки на паузу, но платежи идут. Сверяй открытые заказы через API и обрабатывай сохранённую доставку после восстановления. Не выполняй заказ по перенаправлению браузера или скриншоту клиента.