Кошелёк и подтверждение оплаты
Пополнение, сверка статуса, банковский перевод и повторные запросы
Перед интеграцией
Проверьте включение кошелька, платёжного модуля и шлюза, валюту и пределы суммы в своей CMS. Операции относятся к активному профилю CMS. Чтение баланса и транзакций требует finance.view; создание пополнения, сверка и вывод — владельца профиля.
Баланс читается через GET /api/v1/wallet/. Устаревшая Swagger-аннотация /wallet/balance не соответствует текущей регистрации. GET /api/v1/wallet/gateways возвращает доступные шлюзы; не выбирайте gateway по названию установленного модуля без проверки этого списка.
Пополнение
- Отправьте
POST /api/v1/wallet/topupс положительнойamountиgatewayиз доступного списка. - Сохраните
external_idответа: для этой операции он заменяется сервером на ID транзакции CMS, это не ID платежа провайдера. - Откройте
payment_urlили штатный виджет изwidget, если это предусмотрено выбранным шлюзом. - После возврата прочитайте
GET /api/v1/wallet/topups/{id}. Признак в return URL не подтверждает оплату. - После подтверждения повторно прочитайте баланс и историю
GET /api/v1/wallet/transactions.
Пример тела для тестового шлюза, реально включённого в вашей установке:
{"amount":100,"gateway":"<enabled gateway slug>"}Ответ HTTP 200 содержит external_id, status, необязательные payment_url и widget. status этого ответа описывает запуск платёжного интерфейса; итоговый статус берите из WalletTopUpStatus:
{
"transaction_id":"<CMS transaction UUID>",
"amount":100,
"currency":"RUB",
"status":"pending",
"payment_gateway":"<gateway slug>",
"balance_after":0
}Значения статуса транзакции: pending, completed, failed, cancelled. Только чтение статуса и состояния баланса подтверждает результат. Сумма и валюта должны совпадать с сохранённой транзакцией, а не с пользовательскими параметрами страницы возврата.
Сверка с провайдером
POST /api/v1/wallet/topups/{id}/reconcile принимает JSON с provider_transaction_id. В текущей реализации сверка поддерживает CloudPayments, Т-Банк и Ozon Pay. Для Т-Банка используется сохранённый сервером PaymentId; чужое переданное значение отклоняется. Настройка остальных провайдеров и их webhook относится к конкретному модулю.
| Ответ | Значение |
|---|---|
| 200 | Возвращён подтверждённый или другой завершённый статус; читайте status |
| 202 | Провайдер ещё не подтвердил пополнение; статус pending |
| 400 | Неверный UUID, тело или provider transaction ID |
| 404 | Транзакция не найдена в области текущего профиля |
| 409 | Не совпали провайдер, ссылка, сумма, валюта либо допустимое состояние |
| 503 | Проверка временно недоступна; зачисление не подтверждено |
Одновременная сверка и webhook подтверждают транзакцию через общий механизм с блокировкой и проверками суммы, валюты и внешнего ID. Это не делает создание пополнения идемпотентным: повторный POST /wallet/topup может создать новый платёж. После сетевой ошибки сначала найдите существующую операцию в истории и уточните результат.
Банковский перевод
Для банковского перевода используйте POST /api/v1/wallet/topups/bank-transfer с данными плательщика по контракту модуля. Общий /wallet/topup с bank_transfer отвечает 409 bank_transfer.payer_required; ненастроенный модуль — 409 bank_transfer.needs_configuration.
Тело CreateBankTransferTopUpInput: amount_minor — целое число копеек от 1 до 1 000 000 000 с дополнительными лимитами кошелька, currency="RUB", payer. В payer есть kind, name, inn, kpp, ogrn, address, email, phone. Имя после удаления крайних пробелов — 2–300 символов. Условия зависят от kind:
kind | Обязательные сведения |
|---|---|
legal_entity | ИНН из 10 цифр с правильной контрольной суммой, КПП, ОГРН, адрес |
individual_entrepreneur | ИНН из 12 цифр с правильной контрольной суммой, ОГРНИП, адрес; КПП не передаётся |
individual | Email или телефон; поля ИНН/КПП/ОГРН не передаются; плательщики этого вида должны быть разрешены настройкой модуля |
Успех — HTTP 201 и transaction_id, invoice_number, amount_minor, currency, invoice_date, valid_until. Это отдельный контракт с суммой в копейках; его нельзя заменить телом обычного пополнения с amount.
Счёт и его PDF доступны владельцу по /api/v1/wallet/transactions/{id}/bank-transfer/invoice и /api/v1/wallet/transactions/{id}/bank-transfer/invoice.pdf. Получение счёта не подтверждает поступление денег. Проверка подтверждающих материалов и решение администратора требуют соответствующих billing-разрешений. Не заменяйте их вызовом клиентской сверки или изменением статуса в интерфейсе.
Административное чтение /api/v1/admin/payments/bank-transfers требует billing.view, решение POST /{id}/review — billing.manage. BankTransferReviewInput содержит action (confirmed или cancelled), bank_reference, received_amount_minor, received_at, cancellation_reason, note, attested; проверяются подтверждающие сведения и сумма. Ответ содержит transaction_id, status, balance_after_minor, idempotent; старое поле balance_after оставлено для совместимости. Внешние поступления сверяются до решения; повтор не создаёт второго зачисления. Подготовка счёта, подтверждение денег и статус чека — отдельные этапы.
Вывод, возвраты и заказы
POST /api/v1/wallet/withdraw принимает WithdrawalInput: положительную amount, непустой method, details — объект со строковыми значениями реквизитов. Обработчик отдельно проверяет сумму и метод; набор ключей details согласуется с механизмом выплаты. Успех — HTTP 201 и WithdrawalRequest; недостаточный баланс — 400, отключённый вывод или блокировка аккаунта — 403. В транзакции средства сразу вычитаются из доступного баланса, а заявка получает pending. Читайте свои заявки через GET /api/v1/wallet/withdrawals с page, per_page и разрешением finance.view.
Решение администратора — PUT /api/v1/admin/payments/withdrawals/{id} с approve и admin_note, разрешение billing.manage. В текущем общем сервисе одобрение меняет pending непосредственно на completed, отказ — на rejected с возвратом зарезервированной суммы. Этот обработчик записывает решение в CMS и сам не вызывает внешнего провайдера выплаты. Поле approved существует в модели, но промежуточный этап здесь не создаётся. Успешный ответ решения — {"status":"ok"}; итоговую заявку и фактическую внешнюю выплату проверяйте отдельно. Для запланированной реферальной выплаты дополнительно проверяются дата и причина финансового решения. Контракты реквизитов, привязки карты, СБП и payout-модуля зависят от провайдера.
Оплата заказа, escrow, возврат покупателю и пополнение кошелька имеют разные ID и состояния. Не передавайте ID заказа вместо ID пополнения. Для товарных и фриланс-заказов используйте сценарии продуктов и контракт установленного модуля.
Проверяйте денежные сценарии в штатном sandbox провайдера: pending→completed, отказ, несовпадение суммы/валюты, повторный callback и недоступность сервиса. Реальный платёж не требуется для чтения документации. Общие правила диагностики — в проверке интеграции.