Pagos sin interfaz: checkout por depósito en una sola llamada
Si estás construyendo tu propio checkout — una app móvil, una plataforma asociada, una tienda personalizada — la página alojada /pay/{id} no siempre encaja. Ya tienes un flujo de wallet. Ya sabes en qué cadena y con qué token quiere pagar tu cliente. Lo que realmente quieres es una sola llamada de API que te devuelva una dirección de depósito y el monto exacto a enviar.
Para eso existe POST /api/payments/headless.
La forma de la llamada
Una entrada. Una salida.
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": "Pedido #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"
}
Tu app ya tiene todo lo que necesita: dile al cliente que envíe exactamente amount_raw del token de origen a address. Renderiza un QR desde payment_uri si quieres. Haz polling a GET /api/payments/{id}/status hasta el estado final.
Dos tipos de ruta, una sola forma
- Directa — mismo token, misma cadena (el cliente paga USDT en Polygon y tú liquidas USDT en Polygon). La dirección de depósito es tu wallet. Sin comisiones de puente ni esperas.
- Depósito de swap / bridge — una ruta entre tokens o entre cadenas donde el cliente envía una sola transacción a una dirección de entrada y el token de liquidación llega a tu wallet. Sin firmar ninguna orden.
Las rutas que requieren que el cliente firme una orden tipada o envíe una transacción de swap on-chain no se soportan en este endpoint — si esa es la única ruta disponible, recibirás un 422. Para esos casos, usa la página alojada /pay/{id} o el trío de bajo nivel /quotes + /build-order + /submit-order.
Lo que aún te toca hacer
Dos cosas:
1. Consigue el tx hash si puedes. Para depósitos de swap/bridge no hace falta hacer nada — el monitor en segundo plano detecta el depósito y marca el pago como completado. Para rutas directas, el monitor sólo verifica cuando tiene un tx hash, así que llama a POST /api/payments/{id}/confirm con { "tx_hash": "0x..." } cuando el cliente transmita la transacción. Si tu UI de wallet te da el hash (la mayoría lo hace), es una sola línea.
2. Haz polling del estado. GET /api/payments/{id}/status devuelve el estado actual más un tx hash cuando el pago llegue. El webhook que configuraste en tu canal dispara los mismos eventos (payment.completed, payment.failed, etc.) — usa lo que encaje con tu arquitectura.
Cuándo usar cada uno
| Lo que estás construyendo | Usa |
|---|---|
| Una integración estilo WooCommerce / Shopify con redirección | POST /api/payments → /pay/{id} |
| Un checkout personalizado donde controlas el flujo de wallet | POST /api/payments/headless |
| Necesitas ofrecer varias rutas de swap y que el usuario elija | POST /api/payments + /quotes + /build-order |
El endpoint headless es más estrecho a propósito. Elige automáticamente la mejor ruta por depósito, se compromete con ella y te devuelve una dirección de depósito. Si necesitas más control — velocidad vs precio, varias opciones de ruta, flujos de orden firmada — los endpoints granulares siguen ahí.
Referencia completa en la documentación de la API. Preguntas bienvenidas.