tgpay cryptoAPI
crypto-payapiwebhookssignature

Referencia de la API: webhooks

3 min de lecturaActualizado el 11 ago 2026

Los webhooks le envían los eventos a tu servidor en el momento en que ocurren. Pon la URL del webhook en tu app, en Más → API para comerciantes; a partir de ahí la plataforma hace POST de un cuerpo JSON firmado por cada evento al que estés suscrito.

El envoltorio

{
  "update_id": 123,
  "update_type": "invoice_paid",
  "request_date": "2026-08-11T12:00:00Z",
  "payload": {  }
}

update_id se mantiene estable entre reenvíos del mismo evento: basa tu deduplicación en él. request_date se sella en cada intento de entrega. payload es el objeto completo del tipo de evento: el objeto de factura para los eventos de facturas, el objeto de cheque o el objeto de suscripción (las formas están en las páginas de referencia correspondientes).

Tipos de eventos

update_typeSe dispara cuandoPayload
invoice_paidse paga una factura — siempre se entregaobjeto de factura
invoice_expireduna factura pasa su fecha límite sin pagarseobjeto de factura
check_activatedse canjea uno de tus chequesobjeto de cheque
refund_completedse ejecuta un reembolsoobjeto de factura con los campos refunded_*
subscription_activatedun usuario aprueba un planobjeto de suscripción
subscription_chargedse cobra un período — charge.kind dice cuál: initial, renewal o resubscribeobjeto de suscripción + charge: {period_no, kind, asset, amount, fee, paid_at}
subscription_cancelleduna suscripción se cancela por cualquiera de los dos ladosobjeto de suscripción
subscription_expiredel período de gracia se agota sin pagoobjeto de suscripción

Todo salvo invoice_paid es opcional (una extensión sobre Crypto Bot: un consumidor con forma estricta de Crypto Bot nunca se topa con un update_type desconocido salvo que lo hayas pedido). Actívalos por app en Eventos de webhook adicionales, en la pantalla API para comerciantes: los interruptores aparecen una vez que hay una URL de webhook, y están etiquetados con los identificadores crudos de la tabla de arriba.

Verificar la firma

Cada entrega lleva la cabecera TgPayCrypto-API-Signature (Crypto-Pay-API-Signature es un alias de compatibilidad con el mismo valor): el HMAC-SHA256 en hexadecimal del cuerpo crudo de la petición, con clave el resumen SHA-256 del token de API principal de tu app. Es el esquema de Crypto Bot, así que el código de verificación que ya tengas funciona sin cambios:

import hashlib, hmac

secret = hashlib.sha256(API_TOKEN.encode()).digest()
expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, headers["TgPayCrypto-API-Signature"])

Verifica sobre los bytes crudos recibidos: un análisis reserializado puede diferir byte a byte y hacer fallar la comprobación. Solo firma el token principal; los tokens restringidos nunca firman. Renovar el token principal vuelve a fijar al instante la clave de firma de los webhooks, así que actualiza el secreto en tu servidor en el mismo movimiento.

Entrega y reintentos

  • Una entrega cuenta como exitosa con cualquier respuesta 2xx en menos de 10 segundos.
  • Cualquier otra cosa —un estado de error, un tiempo agotado, un fallo de conexión— se reintenta con retroceso exponencial: el primer reintento a los 10 segundos aproximadamente, duplicando el intervalo hasta 8 horas, con hasta 17 intentos repartidos en unos 3 días.
  • Después del último intento la entrega se descarta. La URL del webhook en sí nunca se desactiva automáticamente: un endpoint inestable no desuscribe tu app en silencio.
  • Como hay reintentos, tu manejador tiene que ser idempotente: deduplica por update_id antes de actuar.

⚠️ Verifica antes de despachar

Cualquiera puede hacer POST a tu URL de webhook. Hasta que la comprobación de la firma pase, trata el cuerpo como entrada no confiable: no despaches un pedido, no le acredites nada a un usuario, no marques nada como pagado. El orden seguro es: verificar la firma → deduplicar por update_id → actuar.