Integración de API de pagos cripto: facturas, firmas y webhooks
Una guía práctica para desarrolladores: una petición firmada para crear la factura, un endpoint de webhook para recibir el estado y los detalles de seguridad que lo hacen fiable.

Una integración de API de pagos cripto necesita dos piezas: una petición desde el servidor que crea una factura para cada pedido y devuelve una URL de checkout, y un endpoint de webhook que recibe actualizaciones de estado firmadas cuando el pago se detecta y se confirma en la blockchain. Con mistKET ambas son HTTPS y JSON simples, firmados con HMAC-SHA256: no necesitas ningún SDK.
Esta guía recorre el flujo completo con código y después repasa los detalles de seguridad y fiabilidad que separan una demo de un sistema en producción.
La arquitectura de una API de pagos cripto en una imagen
Toda integración de API de pagos cripto sigue el mismo ciclo de cinco pasos:
- Pedido creado: tu backend llama a
POST /api/v1/invoicescon importe, moneda, ID de pedido y URL de callback. - Redirección: envías al cliente a la
checkout_urldevuelta. - Pago: el cliente elige una red y paga en la página alojada; el tipo de cambio queda bloqueado durante la vida de la factura.
- Webhook: mistKET envía por POST
invoice.paid,invoice.confirmedo un evento de excepción a tu URL de callback. - Entrega: verificas la firma, marcas el pedido como pagado y entregas.
Tu API key, tu API secret y tu webhook secret se emiten en el panel del comercio una vez aprobada tu cuenta. La referencia completa está en el panel, en la sección API.
Paso 1: firma y envía la petición de factura
Cada petición a la API lleva tres cabeceras. La firma es el HMAC-SHA256 en hexadecimal de la cadena {timestamp}.{raw body} usando tu API secret:
POST /api/v1/invoices
X-Api-Key: mp_live_…
X-Api-Timestamp: 1760000000
X-Api-Signature: hex(hmac_sha256("{ts}.{body}", secret))
{
"amount": "184.50",
"currency": "USD",
"order_id": "2041",
"callback_url": "https://yourstore.com/webhooks/mistket"
} Una versión mínima en PHP tiene este aspecto:
$body = json_encode([
'amount' => '184.50', 'currency' => 'USD',
'order_id' => '2041',
'callback_url' => 'https://yourstore.com/webhooks/mistket',
]);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . '.' . $body, $apiSecret);
// envía $body con X-Api-Key, X-Api-Timestamp, X-Api-Signature Firma exactamente los bytes que envías. Volver a codificar el JSON después de firmar (con otros espacios u otro orden de claves) es la causa número uno de los errores de firma.
Paso 2: redirige al checkout alojado
Una llamada correcta devuelve 201 Created con el UUID de la factura, su estado (new) y una checkout_url. Guarda el UUID junto a tu pedido y redirige al cliente. La página alojada muestra el importe exacto, un código QR, una cuenta atrás y el estado en vivo, y funciona en móvil. El cliente elige allí la red (USDT en TRON, BNB Smart Chain, Ethereum o Arbitrum, además de TRX, BNB y ETH), salvo que fijes la red en la llamada a la API.
Además de crear facturas, la API permite listarlas, consultarlas y cancelarlas, algo útil cuando cambia un carrito o se abandona un pedido.
Paso 3: recibe y verifica los webhooks de pago cripto
Cuando cambia el estado, mistKET envía un POST con JSON a tu URL de callback con estas cabeceras:
| Cabecera | Función |
|---|---|
X-Mistket-Event | Nombre del evento, p. ej. invoice.confirmed |
X-Mistket-Timestamp | Hora Unix usada en la firma |
X-Mistket-Signature | sha256= + HMAC-SHA256 de {timestamp}.{raw body} con tu webhook secret |
X-Mistket-Delivery | ID de entrega, práctico para los logs |
Verificación en PHP:
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_MISTKET_TIMESTAMP'] ?? '';
$got = $_SERVER['HTTP_X_MISTKET_SIGNATURE'] ?? '';
$exp = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $webhookSecret);
if (!hash_equals($exp, $got) || abs(time() - (int) $ts) > 300) {
http_response_code(401); exit;
}
$event = json_decode($raw, true); Usa una comparación de tiempo constante (hash_equals en PHP, hmac.compare_digest en Python, crypto.timingSafeEqual en Node.js) y rechaza los timestamps antiguos para bloquear ataques de repetición. Para conocer el fundamento, consulta la RFC 2104 (HMAC).
Ejemplo de payload de webhook
Un pago confirmado llega como un documento JSON compacto. Los campos que más usarás son el evento, tu ID de pedido, el estado y los importes esperado y recibido:
POST https://yourstore.com/webhooks/mistket
X-Mistket-Event: invoice.confirmed
X-Mistket-Signature: sha256=…
{ "event": "invoice.confirmed", "data": {
"order_id": "2041", "status": "confirmed",
"pay_amount": "184.5", "paid_amount": "184.5",
"pay_currency": "USDT", "network": "TRC20" } } Guarda pay_currency y network con el pedido. Son útiles para la contabilidad y para futuras conversaciones de soporte.
Verificación en Node.js y Python
La misma comprobación en otros dos lenguajes populares:
// Node.js (Express con express.raw para esta ruta)
const exp = 'sha256=' + crypto.createHmac('sha256', secret)
.update(ts + '.' + rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(sig));
# Python
exp = 'sha256=' + hmac.new(secret.encode(), f'{ts}.{raw}'.encode(),
hashlib.sha256).hexdigest()
ok = hmac.compare_digest(exp, sig) En ambos casos, asegúrate de leer el cuerpo bruto de la petición. Muchos frameworks parsean el JSON automáticamente; una vez parseado y serializado de nuevo, los bytes ya no coinciden con la firma.
Pruebas en local
Los webhooks necesitan una URL HTTPS pública, así que un portátil local no puede recibirlos directamente. Hay dos opciones prácticas: desplegar pronto el handler en un servidor de staging o exponer temporalmente tu puerto local con una herramienta de túnel. Crea facturas pequeñas que apunten al callback de staging y revisa los logs de entrega en el panel del comercio para ver exactamente qué se envió y qué respondió tu servidor.
Intenta provocar cada tipo de evento al menos una vez durante las pruebas: paid, confirmed, underpaid y expired. Cuando cada rama de tu handler se haya ejecutado con un webhook real, quedará muy poco que pueda sorprenderte en producción, y sabrás exactamente cómo se ven los logs de entrega cuando algo falle.
Paso 4: gestiona cada estado
El payload de un webhook incluye el ID de pedido, el estado, el importe esperado (pay_amount), el importe recibido (paid_amount), la moneda y la red. Asocia cada evento a una acción:
| Evento | Significado | Acción habitual |
|---|---|---|
invoice.paid | Transferencia detectada, confirmaciones pendientes | Mostrar "pago recibido, confirmando" |
invoice.confirmed | Confirmaciones necesarias alcanzadas | Marcar como pagado y entregar |
invoice.underpaid | Por debajo de tu tolerancia | Esperar el complemento o contactar al cliente |
invoice.overpaid | Más de lo esperado | Entregar; decidir qué hacer con la diferencia |
invoice.expired | Ningún pago válido a tiempo | Liberar stock, dejar el pedido sin pagar |
La tolerancia de pago insuficiente, los pagos parciales que suman el total y los pagos tardíos dentro de un periodo de gracia los gestiona mistKET; tu código solo reacciona al resultado final.
Fiabilidad: reintentos e idempotencia
Si tu endpoint está caído o devuelve un error, los webhooks se reintentan con back-off durante horas. Eso significa que a veces recibirás el mismo evento dos veces. Haz que tu handler sea idempotente por ID de pedido:
- Responde rápido con un 2xx y procesa el trabajo pesado en una cola.
- Antes de entregar, comprueba si el pedido ya está marcado como pagado.
- Registra el ID de entrega y el evento para poder rastrear incidencias; el panel también muestra los logs de entrega de webhooks.
Lista de comprobación de seguridad
Una integración de API de pagos cripto mueve dinero, así que trátala como cualquier otro código de pagos:
- Guarda el API secret y el webhook secret solo en el servidor, nunca en el código front-end ni en apps móviles.
- Restringe el acceso a la API con la lista de IPs permitidas del panel.
- Rechaza las peticiones fuera de una ventana corta de timestamp.
- Configura la caducidad de las facturas según tu lógica de reserva de stock.
- Trata los importes como cadenas o decimales, nunca como floats.
Próximos pasos
Esa es la integración completa de una API de pagos cripto: una petición firmada, un webhook verificado y un mapa de estados. Para ver el mismo flujo desde el lado no técnico, lee cómo aceptar pagos con criptomonedas en una web. ¿Estás creando un bot en lugar de una web? Consulta cómo aceptar pagos cripto en un bot de Telegram. Solicita tus claves de API en Telegram @mistnetwork, revisa el ejemplo en la sección para desarrolladores y gestiona tus claves en el acceso de comercios.


