FINORA Core · Concepts
Webhooks firmados del core: el core te avisa
This content is not available in your language yet.
El problema: preguntar cada minuto «¿hay algo nuevo?»
Sección titulada «El problema: preguntar cada minuto «¿hay algo nuevo?»»Tu conciliador necesita enterarse de cada asiento contable. Si pregunta al core cada minuto, el 99 % de las preguntas vuelven vacías y, aun así, se entera tarde. Si pregunta cada segundo, carga al core sin necesidad.
La idea: que el core avise
Sección titulada «La idea: que el core avise»Con un webhook, tu sistema registra una URL y los tipos de evento que le interesan. Cuando ocurre uno, el core le
hace un POST firmado. Tu sistema solo trabaja cuando hay algo que hacer.
Los avisos salen del registro de eventos del core (el outbox): el evento se escribe en la misma transacción que la operación que lo produce. Si el asiento se revierte por un error, el evento tampoco existe. Nunca recibes el aviso de algo que no ocurrió.
flowchart LR
OP["Operación del core<br/>(un asiento, una transacción)"] -->|"mismo commit"| OB[("Registro de eventos")]
OB --> D["Despachador<br/>(cada 2 s)"]
D -->|"una entrega por suscripción"| E[("Entregas")]
E -->|"POST firmado"| R["Tu receptor<br/>HTTPS"]
R -->|"2xx"| E
Qué eventos hay
Sección titulada «Qué eventos hay»| Tipo | Cuándo |
|---|---|
AccEntryPosted | El core contabilizó un asiento |
TransactionPosted | Se registró una transacción de cliente |
AccountChanged | Se creó o cambió una cuenta de cliente |
CustomerChanged | Se creó o cambió un cliente |
Una suscripción pide una lista de tipos (hasta 50) o * para todos. Recibe los eventos ocurridos desde que existe,
no los anteriores.
El aviso
Sección titulada «El aviso»Un POST (o PUT o PATCH, si la suscripción lo pide) con Content-Type: application/json:
{ "webhookId": "whd_7c1e4b0f2a9d4c8e9b3f6a1d2e5c7b90", "eventId": "0b7f3d2a-6c1e-4f8a-9d2b-5e4c3a1f0e9d", "eventType": "AccEntryPosted", "occurredAt": "2026-09-19T14:05:12.481Z", "cursor": "48213-1052", "aggregateType": "AccEntry", "aggregateId": "5a2e9c1b-3d4f-4a6b-8c7d-9e0f1a2b3c4d", "data": { "eventType": "AccEntryPosted", "eventVersion": "1", "payload": { "cia": "001", "currency": "VES", "baseAmount": "116.00", "conceptCode": "GL-MANUAL" } }}data es el sobre del evento tal como lo escribió el core; su contenido depende del tipo.
| Cabecera | Qué es |
|---|---|
X-Finora-Signature | t=<segundos>,v1=<hex>: la firma. Verifícala siempre |
X-Finora-Webhook-Id | Identificador de la entrega. Es el mismo en todos los reintentos: úsalo para no procesar dos veces |
X-Finora-Event-Type | El tipo de evento |
X-Finora-Delivery-Attempt | Número de intento: 1, 2, 3… |
User-Agent | FINORA-Webhooks/1.0 |
| Las tuyas | Hasta 20 cabeceras propias de la suscripción (por ejemplo un Authorization de tu receptor). No pueden pisar las anteriores ni las de transporte |
La firma
Sección titulada «La firma»v1 = hex( HMAC-SHA256( secreto, t + "." + cuerpo ) )tes el momento del envío, en segundos desde 1970. Cada intento lleva untnuevo.- El secreto es uno por suscripción, empieza por
whsec_y se muestra una sola vez: al crear la suscripción o al rotarlo. El core lo guarda cifrado. - Tu receptor recalcula la firma sobre el cuerpo crudo, la compara en tiempo constante y rechaza un
tque se aleje de su reloj más de su tolerancia (cinco minutos es una buena cifra). Así nadie puede reenviarte un aviso viejo.
Es el mismo esquema t / v1 de los avisos de FINORA Checkout: si ya lo implementaste allí, tu código sirve. Cómo
hacerlo paso a paso, en Java y en Node: Recibir y verificar los webhooks del core.
Reintentos
Sección titulada «Reintentos»| Respuesta de tu receptor | Lo que hace el core |
|---|---|
2xx | Entregado (DELIVERED) |
5xx, 408, 429, tiempo agotado, error de red o de TLS | Reintenta más tarde (FAILED con su próxima hora) |
3xx y el resto de 4xx | No reintenta (DEAD): es un error de configuración del receptor. Las redirecciones no se siguen |
La espera entre intentos se duplica: 30 s, 1 min, 2 min, 4 min, 8 min, 16 min y 32 min con los valores por defecto,
con un tope de 6 horas. Tras 8 intentos la entrega queda DEAD. Cada intento espera hasta 5 s para conectar y
10 s por la respuesta: responde 2xx rápido y procesa después.
stateDiagram-v2 [*] --> PENDING PENDING --> DELIVERED: 2xx PENDING --> FAILED: 5xx, 408, 429 o sin respuesta FAILED --> DELIVERED: 2xx en un reintento FAILED --> FAILED: falla otra vez FAILED --> DEAD: 8 intentos PENDING --> DEAD: 3xx o 4xx DEAD --> PENDING: reenvío manual
El orden no está garantizado entre entregas que se reintentan, y una entrega puede llegarte más de una vez. Por eso:
deduplica por X-Finora-Webhook-Id y, si el orden importa, usa el cursor del cuerpo o lee el
streaming de eventos.
Circuit breaker por suscripción
Sección titulada «Circuit breaker por suscripción»Si tu receptor se cae, no tiene sentido seguir golpeándolo. Tras 5 fallos reintentables seguidos el circuito de
esa suscripción se abre y el core deja de enviarle durante 5 minutos. Pasada la pausa manda una sola entrega de
prueba: si sale bien, el circuito se cierra y la cola fluye; si falla, vuelve a abrirse. Un 4xx no cuenta como fallo:
tu receptor está arriba y está rechazando, y abrir el circuito no lo arregla.
Las demás suscripciones no se enteran: cada una tiene su propio circuito.
Destinos permitidos
Sección titulada «Destinos permitidos»- Solo
https. - Sin usuario ni clave dentro de la URL: para autenticarte ante tu receptor usa una cabecera propia.
- Nunca
localhost, direcciones de bucle local ni de enlace local (incluida la de metadatos de la nube). Se valida al guardar y otra vez antes de cada envío, por si cambia el DNS. Las redes privadas del banco sí se admiten.
Webhook o streaming
Sección titulada «Webhook o streaming»| Webhook (empuje) | Streaming de eventos (tirón) | |
|---|---|---|
| Quién inicia | El core | Tu sistema |
| Necesitas | Un receptor HTTPS publicado | Solo salida hacia el gateway |
| Orden | No garantizado entre reintentos | Estricto, por cursor |
| Si tu sistema se cae | Reintentos y luego DEAD con reenvío manual | Retomas desde tu último cursor confirmado |
| Bueno para | Reaccionar rápido a un hecho | Replicar o conciliar sin perder nada |
Para seguir
Sección titulada «Para seguir»- Recibir y verificar los webhooks del core: alta de la suscripción, verificación de la firma y las pantallas de la consola.
- Consumir el streaming de eventos.