Esta guía documenta la integración completa de TronDealer, la pasarela de pagos con stablecoins operada por QvaPay. Al terminar tendrás un backend capaz de aceptar USDT y USDC en BSC, Ethereum y Polygon, con detección automática de depósitos, notificaciones firmadas por webhook y sweep de fondos al wallet principal.
Si vienes de otra pasarela (Coinbase Commerce, BitPay, NOWPayments), la API de TronDealer cubre el mismo flujo —registro, checkout, webhook, reconciliación— pero sin volatilidad de precio (los clientes pagan directamente en stablecoins) y con soporte nativo para mercados hispanos vía QvaPay.
- Un backend que pueda hacer peticiones HTTPS y procesar JSON.
- Una URL pública con HTTPS para recibir webhooks (puedes usar
ngrok,cloudflaredo un túnel en dev). - Conocimientos básicos de HMAC-SHA256 para validar firmas.
Visión general del flujo
El ciclo de vida de un pago tiene cuatro estados. Todo lo que integres debe entender esta progresión:
- detected — TronDealer ve el depósito en la red correspondiente (BSC, ETH o Polygon).
- confirmed — La transacción acumula suficientes confirmaciones on-chain (por defecto 15 en BSC).
- notified — Se dispara el webhook POST a tu URL configurada, firmado con HMAC si definiste
webhook_secret. - swept — Los fondos se barren automáticamente al wallet principal o cuenta QvaPay que hayas configurado.
Los 6 pasos
- 1
1. Registra tu negocio vía API
El registro es público y no requiere aprobación manual. Necesitas un token Cloudflare Turnstile (CAPTCHA) obtenido desde el widget en el frontend, pero si estás haciendo pruebas desde backend puedes registrarte a través del formulario web en
/onboardy luego autenticarte.POSThttps://trondealer.com/api/v2/clients/register-publicAuthnone (Turnstile token)curl -X POST https://trondealer.com/api/v2/clients/register-public \ -H "Content-Type: application/json" \ -d '{ "name": "Mi Tienda", "webhook_url": "https://mi-backend.com/webhooks/trondealer", "webhook_secret": "un-secreto-largo-y-aleatorio", "min_confirmations": 15, "sweep_wallet": "0xABC...123", "payout_method": "wallet", "turnstile_token": "..." }'La respuesta incluye
client.api_keycon prefijotd_seguido de 64 caracteres hex. Guárdalo en tu vault de secretos: esta cabecera es la credencial que autentica todas las llamadas posteriores y no podrás recuperarla.Elige bien el payout_methodAl registrar defines cómo recibes los fondos después del sweep:
wallet(tu dirección EVM personal),qvapay(cuenta QvaPay por usuario o email) ozelle(email o teléfono). Cambiar después requiere editar la configuración desde el dashboard. - 2
2. Asigna una wallet multi-chain
Cada cliente genera wallets EVM bajo demanda. La misma dirección es válida en BSC, Ethereum y Polygon (las tres redes V2 soportadas actualmente).
POSThttps://trondealer.com/api/v2/wallets/assignAuthx-api-key: td_...curl -X POST https://trondealer.com/api/v2/wallets/assign \ -H "x-api-key: td_..." \ -H "Content-Type: application/json" \ -d '{ "label": "Pedido #A-1024" }'Si pasas el mismo
labeldos veces, TronDealer reutiliza la wallet existente (200 OK). Esto te permite tratar ellabelcomo idempotencia del lado de tu sistema: el ID de pedido, el user ID, etc.La clave privada de la wallet se almacena cifrada en nuestra base de datos y nunca se expone por API. TronDealer orquesta todas las operaciones on-chain (sweep, gas funding) por ti.
- 3
3. Consulta el balance on-chain
Antes de marcar un pedido como pagado, puedes verificar el balance en vivo de una wallet. El endpoint consulta directamente los contratos de USDT y USDC en las tres redes y devuelve saldos decodificados.
POSThttps://trondealer.com/api/v2/wallets/balanceAuthx-api-key: td_...balance.sh curl -X POST https://trondealer.com/api/v2/wallets/balance \ -H "x-api-key: td_..." \ -H "Content-Type: application/json" \ -d '{ "address": "0xABC...123" }'Respuesta típica:
balance-response.json { "success": true, "balances": { "bsc": { "native": "0.012", "usdt": "50.0", "usdc": "0.0" }, "eth": { "native": "0.0", "usdt": "0.0", "usdc": "25.5" }, "pol": { "native": "0.0", "usdt": "0.0", "usdc": "0.0" } } }En la mayoría de los casos no necesitas pollearlo: el webhook de confirmación (paso 5) llega automáticamente cuando hay un depósito. Úsalo solo para reconciliación manual o dashboards internos.
- 4
4. Lista transacciones con filtros y paginación
Para mostrar el historial de un cliente o reconciliar depósitos contra tu ERP, lista las transacciones asociadas a sus wallets.
POSThttps://trondealer.com/api/v2/wallets/transactionsAuthx-api-key: td_...list-transactions.js const res = await fetch('https://trondealer.com/api/v2/wallets/transactions', { method: 'POST', headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ address: '0xABC...123', status: 'confirmed', // detected | confirmed | notified | swept limit: 20, offset: 0, }), }) const { transactions, total } = await res.json()Cada transacción incluye:
tx_hash,block_number,from_address,to_address,asset(USDT/USDC),amountdecodificado,confirmationsactuales,status,network,webhook_sent, y timestamps. - 5
5. Configura y verifica el webhook HMAC
Esta es la parte crítica de cualquier pasarela: garantizar que los webhooks que recibes son auténticos y no fueron inyectados por un tercero con acceso a tu URL.
Si registraste un
webhook_secret, cada POST incluye un headerX-Signature-256con la firma HMAC-SHA256 del body completo. Debes:- Recibir el body raw (antes de parsearlo como JSON).
- Calcular
HMAC-SHA256(secret, raw_body)en hex. - Comparar con el valor del header usando comparación constante (timing-safe).
import crypto from 'node:crypto' import express from 'express' const app = express() const SECRET = process.env.WEBHOOK_SECRET // IMPORTANTE: body raw, no json() app.post( '/webhooks/trondealer', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-signature-256'] const expected = crypto .createHmac('sha256', SECRET) .update(req.body) .digest('hex') if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) { return res.status(401).send('invalid signature') } const event = JSON.parse(req.body.toString()) // event.tx_hash, event.amount, event.asset, event.network, event.status console.log('Pago confirmado:', event) res.status(200).send('ok') } )Nunca uses comparación con `==`Una comparación string igualdad clásica es vulnerable a timing attacks. Usa
crypto.timingSafeEqualen Node,hmac.compare_digesten Python ohash_equalsen PHP. Es un detalle pequeño pero crítico.ReintentosSi tu webhook devuelve un código ≠ 2xx, TronDealer reintenta automáticamente con backoff exponencial. Responde 200 lo antes posible y procesa el evento de forma asíncrona (cola) si tu lógica es pesada.
- 6
6. Entiende el lifecycle end-to-end
Cada depósito atraviesa estos estados. Diseña tu lógica de negocio alrededor de
confirmed(onotified, que implica confirmado), nunca dedetected.Estado Disparador Acción recomendada detectedEl scanner ve el log de Transfer No marcar pedido como pagado aún confirmed≥ min_confirmations bloques Candidato a liberar producto/servicio notifiedWebhook entregado con 2xx Tu sistema ya confirmó recepción sweptFondos movidos al wallet principal Cobro consolidado, listo para contabilidad Las confirmaciones por defecto son 15 (BSC, rápido). Puedes subirlo a 20–30 si manejas montos altos, o bajarlo a 6–10 si priorizas UX. El valor se configura por cliente al registrarte o desde
/dashboard/settings.
Reconciliación y buenas prácticas
Usa un label único por pedido (por ejemplo el ID de orden) al hacer POST /wallets/assign. Esto te da una wallet dedicada por transacción y simplifica la reconciliación: el match es 1:1 entre pedido y dirección de destino.
- Idempotencia: usa
tx_hash + log_indexcomo clave única en tu base de datos. Si un webhook se entrega dos veces (reintento) no procesarás el pago dos veces. - Timeouts: no consideres un pedido "fallido" solo porque la wallet está vacía a los 60 segundos. Los depósitos en BSC tardan ~15s, en ETH varios minutos.
- Logs: guarda el body raw del webhook junto con la firma. Te salvará la vida en un debug.
- Seguridad: la
x-api-keydebe vivir solo en tu backend. Nunca la expongas en frontend ni mobile.
Preguntas frecuentes
Siguiente paso
Con el flujo ya integrado, lo que queda es endurecer la parte operativa: monitorear entregas de webhooks desde /dashboard/webhooks, configurar alertas de sweeps fallidos en /dashboard/sweeps, y ajustar min_confirmations según tu tolerancia a riesgo.
Si necesitas endpoints no cubiertos por V2 (TRON, Solana, Bitcoin), la documentación Swagger lista los endpoints V1 por cadena.