Documentación / Integración

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én http://localhost).
  • El secreto del endpoint se muestra una sola vez. Puede tener hasta 5 endpoints activos; cada evento se envía a todos.

Solicitud

HTTP
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

text
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))
  1. Tome el cuerpo sin procesar: los bytes antes de interpretar el JSON.
  2. Compruebe que X-Webhook-Timestamp no difiere de la hora actual en más de 5 minutos.
  3. Divida X-Webhook-Signature por la coma. La firma es válida si cualquiera de las partes coincide con la esperada (comparación en tiempo constante).
  4. Si no coincide, responda 401 y no haga nada más.

Referencia: secreto whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, cuerpo {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.

Procesamiento

text
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-Id procesados 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 (incluido 3xx: 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

EventoCuándo
invoice.detectedEl pago es visible en la red
invoice.confirmingEl pago está en un bloque y se acumulan confirmaciones
invoice.paidPagada 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.overpaidPagada con excedente
invoice.underpaidConfirmado menos de lo necesario
invoice.awaiting_paymentLa factura vuelve a esperar el pago (por ejemplo, tras la reorganización de su único pago)
invoice.expiredVenció el plazo sin pago
invoice.late_paymentPago con un activo volátil fuera de plazo
invoice.manual_reviewPago en verificación AML
invoice.payment_heldPago retenido por AML (cuarentena)
invoice.reorgedEl bloque con el pago se revirtió y el estado se recalculó (por ejemplo, paid → confirming)
invoice.payment_after_closeLlegó un pago a una factura ya cerrada: no paga el pedido y queda disponible para reembolso
invoice.cancelledFactura cerrada sin pago al ejecutarse un reembolso
refund.sentReembolso 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.

Productos digitales e 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.

  1. Añada el secreto nuevo a su servidor (acepte ambos).
  2. Pulse «Finalizar rotación»: el antiguo se eliminará.
  3. Retire el secreto antiguo de su servidor.