Webhooks
Coinetic notifica a su servidor los cambios de una factura mediante una solicitud POST. Un webhook es una señal de «consulte la factura», no una prueba de pago.
Configuración
- Panel → «Claves y webhooks» → «Añadir». La URL debe ser
https://, con dirección pública y puerto 443 (en el sandbox, tambiénhttp://localhost). - El secreto del endpoint se muestra una sola vez. Puede tener hasta 5 endpoints activos; cada evento se envía a todos.
Solicitud
POST /webhooks/coinetic HTTP/1.1
Content-Type: application/json
User-Agent: cryptopay-webhooks/1
X-Webhook-Id: evt_3f9c…
X-Webhook-Timestamp: 1760000000
X-Webhook-Signature: v1=5d1e…
{"id":"evt_3f9c…","type":"invoice.paid","created_at":"2026-10-12T15:04:05Z","livemode":true,"data":{"invoice_id":"inv_x7k2…","order_id":"ORDER-1001","status":"paid","paid_amount":"49990000"}}X-Webhook-Id se mantiene en los reintentos. Durante una rotación del secreto, X-Webhook-Signature contiene dos firmas separadas por una coma. Los nombres técnicos (cryptopay-webhooks/1) son históricos; no necesita cambiarlos en su código.
Verificación de la firma
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))- Tome el cuerpo sin procesar: los bytes antes de interpretar el JSON.
- Compruebe que
X-Webhook-Timestampno difiere de la hora actual en más de 5 minutos. - Divida
X-Webhook-Signaturepor la coma. La firma es válida si cualquiera de las partes coincide con la esperada (comparación en tiempo constante). - Si no coincide, responda
401y no haga nada más.
Referencia: secreto whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, cuerpo {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.
Procesamiento
verificar la firma → deduplicar por X-Webhook-Id → GET /v1/invoices/{invoice_id}
→ actualizar el pedido según el estado de la API (entrega una sola vez) → responder 2xx- Deduplicación. Un mismo evento puede llegar varias veces. Guarde los
X-Webhook-Idprocesados y marque el pedido como «entregado» en la misma transacción que la entrega. - Responda rápido: en menos de 10 segundos. Envíe el trabajo largo a una cola.
- Códigos de respuesta:
2xx, aceptado;410 Gone, no reintentar esta entrega; cualquier otro código (incluido3xx: las redirecciones no se siguen) o un tiempo de espera agotado provocan un reintento. - Ignore los campos y tipos de eventos que no conozca: la lista irá creciendo.
Encontrará gestores listos para usar en cuatro lenguajes en el inicio rápido.
Reintentos
10 s → 30 s → 2 min → 10 min → 30 min → 1 h → 3 h ×7 → 1 h, con una pequeña variación aleatoria. El último intento se hace aproximadamente un día después. Una entrega fallida puede enviarse de nuevo: panel → «Webhooks» → «Reenviar».
Orden
Los eventos de una misma factura se entregan al endpoint en orden: el siguiente no sale mientras la entrega anterior siga pendiente de reintento. Cuando esta termina, con éxito o sin él, se envían los siguientes. Por eso, básese en el estado de GET /v1/invoices/{id} y no en la secuencia de eventos. Los eventos de facturas distintas son independientes.
Tipos de eventos
| Evento | Cuándo |
|---|---|
invoice.detected | El pago es visible en la red |
invoice.confirming | El pago está en un bloque y se acumulan confirmaciones |
invoice.paid | Pagada y confirmada: puede entregar (tras volver a consultar). data.late: true indica que una stablecoin llegó fuera de plazo y se acreditó automáticamente |
invoice.overpaid | Pagada con excedente |
invoice.underpaid | Confirmado menos de lo necesario |
invoice.awaiting_payment | La factura vuelve a esperar el pago (por ejemplo, tras la reorganización de su único pago) |
invoice.expired | Venció el plazo sin pago |
invoice.late_payment | Pago con un activo volátil fuera de plazo |
invoice.manual_review | Pago en verificación AML |
invoice.payment_held | Pago retenido por AML (cuarentena) |
invoice.reorged | El bloque con el pago se revirtió y el estado se recalculó (por ejemplo, paid → confirming) |
invoice.payment_after_close | Llegó un pago a una factura ya cerrada: no paga el pedido y queda disponible para reembolso |
invoice.cancelled | Factura cerrada sin pago al ejecutarse un reembolso |
refund.sent | Reembolso ejecutado; data.refund incluye el importe, la dirección y el tx_hash |
Los eventos de facturación (billing.*) se refieren a las facturas de comisión de la plataforma: emitida, pagada, vencida, suspensión y levantamiento de la suspensión.
invoice.reorgedUna reorganización después de paid es poco frecuente, pero ocurre. Si entrega el producto al instante, suscríbase a este evento y derive esos casos al equipo de soporte.Rotación del secreto
Panel → «Cambiar secreto»: Coinetic empieza a firmar con ambos secretos.
- Añada el secreto nuevo a su servidor (acepte ambos).
- Pulse «Finalizar rotación»: el antiguo se eliminará.
- Retire el secreto antiguo de su servidor.