Payouts
Pagar saldos liquidados a una wallet — el step-up 2FA para sesiones del dashboard, API keys con step-up, el fee de red fijo y el ciclo de vida del payout.
Última actualización 27 oct 2026
Un payout envía parte o todo el saldo disponible de una cuenta (GET /api/v1/crypto/balances?mode=) en una red y un token a una dirección externa, desde la hot wallet.
curl -X POST "$API/api/v1/crypto/payouts" \
-H "authorization: Bearer $KEY" -H 'content-type: application/json' -H 'idempotency-key: po-2026-10-27-halden' \
-d '{ "account": "halden_type", "network": "POLYGON_AMOY", "token": "USDT",
"amount": "50.00", "destination_address": "0x…" }'Quién puede hacer payouts
Los payouts requieren crypto-payouts:create y se rechazan mientras un platform admin está impersonando al usuario. Además, cada payout pasa por un step-up:
- Dashboard (sesión con cookie): cada payout lleva un código TOTP fresco (
totp_code). El usuario tiene que tener la autenticación de dos factores activada (Settings → Security); si no, el diálogo New payout linkea ahí. Los códigos son de un solo uso, y 5 códigos fallidos en 15 minutos bloquean los step-ups (429 STEP_UP_LOCKED). Un código incorrecto o reutilizado es403. - Las API keys se saltean el código por payout, así que el step-up se mueve al momento en que la key se crea: crear una key con
crypto-payouts:create(ocrypto-payouts:manage, o*:*) requiere una sesión de navegador no impersonada con 2FA y untotp_codeválido. Solo esas keys llevanpayoutStepUpAt; cualquier otra key responde403 STEP_UP_REQUIRED. Las keys creadas antes de esta regla perdieron la capacidad de hacer payouts. El CLI de operador (mint:api-key) también lo setea.
Monto y fee
Un fee de red fijo por payout sale del monto (net_amount = amount − fee) y se registra como REVENUE:PAYOUT_NETWORK_FEE: CRYPTO_PAYOUT_FEE_POLYGON (por defecto 0.10), CRYPTO_PAYOUT_FEE_BSC (0.15), CRYPTO_PAYOUT_FEE_BASE (0.10). El monto tiene que superar el fee. El destino tiene que ser una dirección válida que no sea una de las propias del gateway (los contratos se permiten, a diferencia de los refunds).
Ciclo de vida
| Estado | Significado |
|---|---|
QUEUED | Creado: el monto queda bloqueado en el ledger (MERCHANT_LOCKED) en la misma transacción, así que un payout por encima del saldo es 409 INSUFFICIENT_BALANCE y no crea nada. |
BROADCAST | Firmado y enviado por el worker una vez que la hot wallet puede cubrir net_amount y el gas (si no, espera a los sweeps). La transacción se registra en el journal antes de transmitirse, así que un crash reenvía los mismos bytes; después de 180 s sin receipt se reemplaza con el mismo nonce y fees +20 %. |
COMPLETED | La transacción alcanzó el umbral de confirmaciones de la red; el lock se libera hacia el payout (payout.completed). |
FAILED | Revertida o descartada: el lock vuelve al saldo disponible y el gas se registra como gasto (payout.failed). |
La página Payouts del dashboard muestra los saldos arriba, el historial abajo (contador de confirmaciones en vivo mientras está BROADCAST) y New payout (saldo de origen, monto, destino precargado con la dirección de liquidación de la cuenta, TOTP).
[!WARNING] Cuando una invoice no tiene
merchant, el seller es la cuenta PLATFORM de la organization: su neto se acredita enPARTNER_PAYABLEjunto con el markup, el único saldo del que toman los payouts de PLATFORM. Así, todo payout sale del saldo que el dashboard muestra como disponible.