Headless-платежи: депозитный чекаут за один вызов
Если вы строите собственный чекаут — мобильное приложение, партнёрскую платформу, кастомный магазин — hosted-страница /pay/{id} не всегда подходит. У вас уже есть свой кошельковый флоу. Вы уже знаете, в какой сети и каким токеном хочет заплатить клиент. Что вам на самом деле нужно — один вызов API, возвращающий адрес депозита и точную сумму для отправки.
Именно для этого существует POST /api/payments/headless.
Как это выглядит
Один вызов на входе. Один — на выходе.
curl -X POST https://mutopay.com/api/payments/headless \
-H "X-API-Key: ep_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 25.00,
"currency": "USD",
"description": "Order #1042",
"external_id": "order_1042",
"src_token_symbol": "USDT",
"src_token_address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"src_chain_id": "137",
"src_decimals": 6,
"src_address": "0xCustomerWallet..."
}'
{
"id": "pay_abc123...",
"status": "awaiting_payment",
"route_type": "bridge",
"protocol": "rubic",
"deposit": {
"address": "0xRubicDepositAddress...",
"chain_id": "137",
"chain_type": "evm",
"token_symbol": "USDT",
"token_address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"token_decimals": 6,
"amount_raw": "25100000",
"amount_human": "25.10",
"payment_uri": "ethereum:0x...@137?value=25100000"
},
"bridge": {
"name": "Across",
"estimated_time_ms": 60000,
"src_usd": "25.10",
"bridge_fee_usd": "0.10"
},
"order_id": "rubic_exchange_id...",
"expires_at": "2026-04-14T15:30:00Z"
}
Ваше приложение теперь имеет всё необходимое: скажите клиенту отправить ровно amount_raw исходного токена на address. Если хотите, отрендерите QR из payment_uri. Опрашивайте GET /api/payments/{id}/status до терминального состояния.
Два типа маршрутов, одна структура
- Прямой — тот же токен, та же сеть (клиент платит USDT в Polygon, вы получаете USDT в Polygon). Адрес депозита — ваш кошелёк. Нет комиссий бриджа, нет ожидания.
- Своп / депозит с бриджем — кросс-токенный или кросс-чейн маршрут, где клиент отправляет одну транзакцию на входящий адрес, а расчётный токен поступает в ваш кошелёк. Подписание ордера не требуется.
Маршруты, требующие от клиента подписи типизированного ордера или отправки on-chain-свопа, этим эндпоинтом не поддерживаются — если доступен только такой маршрут, вы получаете 422. Для них используйте hosted-страницу /pay/{id} или связку более низкого уровня /quotes + /build-order + /submit-order.
Что остаётся сделать вам
Два момента:
1. Получите tx hash, если можете. Для депозитов с бриджем ничего делать не нужно — фоновый монитор подхватывает депозит и отмечает платёж завершённым. Для прямых маршрутов монитор верифицирует только после получения tx hash, поэтому вызовите POST /api/payments/{id}/confirm с { "tx_hash": "0x..." } после того, как клиент транслирует транзакцию. Если ваш кошельковый UI возвращает hash (большинство так и делают), это одна строка кода.
2. Опрашивайте статус. GET /api/payments/{id}/status возвращает текущее состояние и tx hash после поступления платежа. Вебхук, настроенный на вашем канале, отправляет те же события (payment.completed, payment.failed и др.) — используйте тот вариант, что подходит вашей архитектуре.
Когда что использовать
| Что вы строите | Используйте |
|---|---|
| Интеграцию в стиле WooCommerce / Shopify с редиректом | POST /api/payments → /pay/{id} |
| Кастомный чекаут, где вы управляете кошельковым флоу | POST /api/payments/headless |
| Нужно предложить несколько вариантов свопа и дать пользователю выбор | POST /api/payments + /quotes + /build-order |
Headless-эндпоинт намеренно уже по возможностям. Он автоматически выбирает лучший маршрут с депозитом, фиксирует его и возвращает адрес депозита. Если вам нужен контроль сверх этого — компромисс между скоростью и ценой, несколько вариантов маршрутов, флоу с подписью ордера — гранулярные эндпоинты по-прежнему доступны.
Полная документация в API docs. Вопросы приветствуются.