> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks y callbacks

> Transmite eventos de Matcher a herramientas externas y recibe callbacks de resolución para mantener tus flujos de conciliación sincronizados.

Los webhooks permiten la comunicación en tiempo real entre Matcher y sistemas externos. Esta guía cubre las notificaciones de eventos salientes y los callbacks de resolución entrantes.

## Descripción general

***

Matcher admite comunicación bidireccional mediante webhooks, manteniendo tus herramientas operativas sincronizadas con cada evento de conciliación en tiempo real. Esto reduce la intervención manual, ayuda a mantener el cumplimiento de SLAs y garantiza una trazabilidad de auditoría continua en todos los sistemas conectados.

* **Webhooks salientes**: el enrutamiento de excepciones envía excepciones a destinos externos — JIRA, ServiceNow o un endpoint HTTP de webhook que tú configuras
* **Callbacks entrantes**: los sistemas externos notifican a Matcher cuando se toman acciones

Cuando una excepción se enruta a un destino de webhook, Matcher entrega una solicitud HTTP firmada a tu endpoint. Los sistemas externos como JIRA o ServiceNow pueden entonces enviar callbacks para actualizar el estado de las excepciones o cerrar elementos automáticamente. Este flujo bidireccional mantiene tus herramientas sincronizadas sin intervención manual.

Más allá del envío de excepciones, Matcher publica su catálogo completo de eventos de ciclo de vida en el backbone de streaming de la plataforma — esos eventos se consumen como un stream, no se entregan como webhooks HTTP.

<Frame caption="Flujo bidireccional entre Matcher y sistemas externos.">
  <img src="https://mintcdn.com/lerian-49cb71fc/ZrZBZTM4DWnrahSd/images/es/d2/matcher-webhooks-callbacks.svg?fit=max&auto=format&n=ZrZBZTM4DWnrahSd&q=85&s=289bf1bf8e8699e88aa3f49e0363add6" alt="Matcher Webhooks Callbacks" width="867" height="520" data-path="images/es/d2/matcher-webhooks-callbacks.svg" />
</Frame>

## Eventos salientes

***

Matcher emite eventos cuando ocurren acciones significativas en el proceso de conciliación. El catálogo a continuación se publica en el backbone de streaming; los eventos de excepción además llegan a endpoints HTTP de webhook a través del [enrutamiento de excepciones](/es/matcher/configuration/matcher-exception-routing).

### Eventos disponibles

El catálogo de eventos de Matcher se define de forma centralizada. Los eventos más comúnmente consumidos se agrupan por dominio a continuación.

**Configuración**

| Evento                           | Disparador                                  | Uso típico                              |
| -------------------------------- | ------------------------------------------- | --------------------------------------- |
| `reconciliation_context.created` | Contexto de conciliación creado             | Sincronización de aprovisionamiento     |
| `reconciliation_context.updated` | Metadatos o estado del contexto modificados | Seguimiento de cambios de configuración |
| `reconciliation_context.deleted` | Contexto eliminado                          | Desmontaje downstream                   |
| `reconciliation_source.created`  | Fuente creada dentro de un contexto         | Incorporación de fuentes                |
| `match_rule.created`             | Regla de coincidencia creada                | Auditoría de cambios de reglas          |
| `match_rule.reordered`           | Prioridades de reglas reordenadas           | Auditoría de cambios de reglas          |

**Descubrimiento (Fetcher)**

| Evento                             | Disparador                                     | Uso típico                  |
| ---------------------------------- | ---------------------------------------------- | --------------------------- |
| `fetcher_connection.synced`        | Instantánea de conexión y esquema sincronizada | Monitoreo de descubrimiento |
| `fetcher_connection.unreachable`   | Conexión marcada como inalcanzable             | Alertas de conectividad     |
| `extraction_request.created`       | Solicitud de extracción creada                 | Monitoreo de extracción     |
| `extraction_request.submitted`     | Extracción aceptada por Fetcher                | Monitoreo de extracción     |
| `extraction_request.completed`     | Extracción completada con artefacto            | Disponibilidad de datos     |
| `extraction_request.failed`        | Extracción fallida                             | Alertas de error            |
| `extraction_request.cancelled`     | Extracción cancelada                           | Monitoreo del pipeline      |
| `extraction_request.bridged`       | Extracción vinculada a un trabajo de ingesta   | Monitoreo del pipeline      |
| `extraction_request.bridge_failed` | Puente hacia la ingesta fallido                | Alertas de error            |

**Ingesta**

| Evento                | Disparador                                       | Uso típico                      |
| --------------------- | ------------------------------------------------ | ------------------------------- |
| `ingestion.completed` | Importación de archivo finalizada                | Monitoreo del pipeline de datos |
| `ingestion.failed`    | Importación de archivo fallida                   | Alertas de error                |
| `transaction.ignored` | Transacción no coincidente marcada como ignorada | Registro de auditoría           |

**Coincidencia**

| Evento                       | Disparador                                | Uso típico                       |
| ---------------------------- | ----------------------------------------- | -------------------------------- |
| `match_run.completed`        | Trabajo de coincidencia finalizado        | Monitoreo de trabajos, reportes  |
| `match_run.failed`           | Trabajo de coincidencia fallido           | Alertas de error                 |
| `match_group.confirmed`      | Grupo de coincidencia confirmado          | Actualizaciones downstream       |
| `match_group.unmatched`      | Coincidencia confirmada revertida         | Seguimiento de correcciones      |
| `transaction.matched`        | Transacción marcada como coincidente      | Registro de auditoría            |
| `transaction.pending_review` | Candidato no automático requiere revisión | Disparadores de cola de revisión |
| `fee_variance.created`       | Variación de comisión detectada           | Investigación de comisiones      |

**Excepciones y disputas**

| Evento                            | Disparador                                       | Uso típico                     |
| --------------------------------- | ------------------------------------------------ | ------------------------------ |
| `exception.assigned`              | Excepción asignada a un responsable              | Notificación al usuario        |
| `exception.resolved`              | Excepción resuelta                               | Sincronización de estado       |
| `exception.dispatched`            | Excepción enviada a un destino externo           | Creación de tickets            |
| `exception.callback_processed`    | Callback externo procesado                       | Sincronización de estado       |
| `exception.force_match_resolved`  | Excepción resuelta mediante coincidencia forzada | Flujos de aprobación           |
| `exception.adjust_entry_resolved` | Excepción resuelta mediante asiento de ajuste    | Registro de auditoría          |
| `exception_comment.added`         | Comentario añadido a una excepción               | Sincronización de colaboración |
| `exception_comment.deleted`       | Comentario de excepción eliminado                | Sincronización de colaboración |
| `dispute.opened`                  | Disputa abierta para una excepción               | Seguimiento de disputas        |
| `dispute.won`                     | Disputa cerrada como ganada                      | Sincronización de estado       |
| `dispute.lost`                    | Disputa cerrada como perdida                     | Sincronización de estado       |
| `evidence.submitted`              | Evidencia enviada a una disputa                  | Seguimiento de disputas        |

**Gobernanza y reportes**

| Evento                     | Disparador                               | Uso típico                   |
| -------------------------- | ---------------------------------------- | ---------------------------- |
| `audit_log.created`        | Entrada de registro de auditoría añadida | Monitoreo de cumplimiento    |
| `archive_metadata.created` | Ciclo de vida de archivado iniciado      | Monitoreo de archivado       |
| `archive.uploaded`         | Objeto de archivo cargado                | Monitoreo de archivado       |
| `archive.completed`        | Archivo verificado y completado          | Monitoreo de archivado       |
| `actor.pseudonymized`      | Mapeo de actor seudonimizado             | Monitoreo de cumplimiento    |
| `export_job.created`       | Trabajo de exportación en cola           | Monitoreo de exportación     |
| `export_job.succeeded`     | Trabajo de exportación completado        | Disponibilidad de descarga   |
| `export_job.failed`        | Trabajo de exportación fallido           | Alertas de error             |
| `export_job.expired`       | Artefacto de exportación caducado        | Ciclo de vida de exportación |

### Payload de entrega de webhook

Los envíos de excepciones a un destino de webhook llevan un payload consistente — `eventId`, `eventType`, `timestamp`, el snapshot de la excepción bajo `data` y la información de enrutamiento/trazado bajo `metadata`:

```json theme={null}
{
  "eventId": "0e8f1c2a-5b6d-4f3e-9a7b-1c2d3e4f5a6b",
  "eventType": "exception.dispatched",
  "timestamp": "2026-01-20T10:30:00Z",
  "data": {
    "exceptionId": "9b2f4e6a-1c3d-4e5f-8a9b-0c1d2e3f4a5b",
    "transactionId": "7a1b3c5d-9e8f-4a2b-b6c7-d8e9f0a1b2c3",
    "severity": "HIGH",
    "status": "PENDING",
    "amount": "15000.00",
    "currency": "USD",
    "reason": "No matching ledger entry found",
    "sourceType": "LEFT",
    "createdAt": "2026-01-20T10:29:15Z",
    "dueAt": "2026-01-23T10:29:15Z"
  },
  "metadata": {
    "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
    "target": "WEBHOOK",
    "queue": "ops-review",
    "ruleName": "high-value-unmatched",
    "assignee": "ops-team"
  }
}
```

`data.dueAt` y los campos de `metadata` `traceId`, `queue`, `ruleName` y `assignee` se omiten cuando no están definidos. Los eventos del catálogo de streaming (las tablas anteriores) siguen sus propios esquemas por evento en el stream de eventos y no se entregan en esta forma HTTP.

## Callbacks entrantes

***

Los sistemas externos envían callbacks a Matcher para actualizar el estado de las excepciones después del procesamiento. El endpoint de callback acepta actualizaciones de estado, notas de resolución y cambios de asignación desde cualquier sistema externo.

### Procesar un callback

El endpoint de callback se autentica con el encabezado `X-Callback-Token` — un token opaco emitido a través de la superficie de [credenciales de callback](#credenciales-de-callback) —, no con un JWT de operador. Todos los campos mostrados abajo son obligatorios; `dueAt` y `updatedAt` aceptan `null`, y `payload` puede ser un objeto vacío:

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/exceptions/{exceptionId}/callback" \
 -H "X-Callback-Token: ***" \
 -H "X-Idempotency-Key: callback-jira-1234" \
 -H "Content-Type: application/json" \
 -d '{
   "callbackType": "status_update",
   "externalSystem": "JIRA",
   "externalIssueId": "RECON-1234",
   "status": "RESOLVED",
   "resolutionNotes": "Verified: amount difference is expected bank wire fee",
   "assignee": "john.doe@company.com",
   "dueAt": null,
   "updatedAt": "2026-01-20T14:30:00Z",
   "payload": {}
 }'
```

El campo `externalSystem` identifica el sistema externo que procesó la excepción. Los valores comunes incluyen `"JIRA"`, `"SERVICENOW"` o `"WEBHOOK"`, pero los callbacks pueden reportar cualquier identificador de sistema. Omitir cualquiera de los nueve campos obligatorios devuelve un `422`.

#### Respuesta

```json theme={null}
{
  "status": "accepted"
}
```

<Tip>Referencia de API: [Procesar callback](/es/reference/matcher/process-exception-callback)</Tip>

Cuando Matcher procesa un callback, actualiza el estado de la excepción y registra la resolución en la pista de auditoría. Usa el encabezado `X-Idempotency-Key` para prevenir el procesamiento duplicado.

### Reintento automático de callbacks fallidos

Si un callback previo para la misma clave de idempotencia falló durante el procesamiento, Matcher intenta automáticamente readquirir el bloqueo de idempotencia y reprocesar el callback. Esto significa que no necesitas generar una nueva clave de idempotencia al reintentar un callback fallido: simplemente reenvía la misma solicitud y Matcher gestiona la recuperación.

El comportamiento de reintento se aplica solo a los callbacks que se marcaron como `failed` internamente. Los callbacks que se completaron correctamente se siguen deduplicando como se espera.

## Credenciales de callback

***

Los callbacks entrantes se autentican con un token bearer opaco que el sistema externo envía en el encabezado `X-Callback-Token`. Estas **credenciales de callback** se emiten, listan, rotan y revocan a través de una superficie CRUD dedicada bajo `/v1/exceptions/callbacks/credentials`. Cada credencial está vinculada al tenant del llamante, y solo el hash SHA-256 del token se almacena del lado del servidor — el token en bruto se retorna **exactamente una vez** al momento de emitir/rotar.

| Acción              | Método y ruta                                                     | Notas                                                                                                                                                                          |
| ------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Emitir credencial   | `POST /v1/exceptions/callbacks/credentials`                       | Crea una credencial y retorna el token en bruto una vez (`201`).                                                                                                               |
| Listar credenciales | `GET /v1/exceptions/callbacks/credentials`                        | Lista los metadatos de credenciales del tenant (nunca los tokens en bruto).                                                                                                    |
| Rotar credencial    | `POST /v1/exceptions/callbacks/credentials/{credentialId}/rotate` | Sustituye atómicamente una credencial activa por una recién emitida (misma etiqueta) y retorna el nuevo token en bruto una vez; la anterior se revoca en la misma transacción. |
| Revocar credencial  | `DELETE /v1/exceptions/callbacks/credentials/{credentialId}`      | Revoca de forma terminal una credencial (`204`); auditada en modo append-only.                                                                                                 |

<Tip>Referencia de API: [Emitir credencial de callback](/es/reference/matcher/mint-callback-credential) | [Listar credenciales de callback](/es/reference/matcher/list-callback-credentials) | [Rotar credencial de callback](/es/reference/matcher/rotate-callback-credential) | [Revocar credencial de callback](/es/reference/matcher/revoke-callback-credential)</Tip>

### Emitir una credencial

El cuerpo de la solicitud es opcional; proporciona `externalSystem` como una etiqueta legible por el operador para el sistema que este token autentica.

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/exceptions/callbacks/credentials" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{ "externalSystem": "stripe" }'
```

La respuesta `201` (`CredentialSecretResponse`) retorna:

| Campo            | Descripción                                                                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `token`          | Token bearer en bruto, expuesto **una vez**. Configúralo como el valor del encabezado `X-Callback-Token` en el sistema externo.           |
| `credentialId`   | ID sustituto de la credencial emitida (usado para rotar/revocar).                                                                         |
| `createdAt`      | Momento de emisión (RFC 3339, UTC).                                                                                                       |
| `externalSystem` | La etiqueta devuelta para confirmación.                                                                                                   |
| `webhookUrlHint` | Forma informativa de la URL de callback entrante para configurar externamente; el marcador `{exceptionId}` se completa por cada callback. |

<Warning>
  El `token` en bruto se muestra solo en las respuestas de emisión y rotación. Almacénalo de forma segura al recibirlo — no se puede recuperar nuevamente. Si se pierde o se filtra, rota o revoca la credencial.
</Warning>

### Rotar una credencial

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/exceptions/callbacks/credentials/{credentialId}/rotate" \
 -H "Authorization: Bearer $TOKEN"
```

La rotación retorna un nuevo `CredentialSecretResponse` (nuevo token en bruto) y revoca la credencial anterior de forma atómica, de modo que los llamantes externos no experimentan ninguna interrupción al intercambiar el token.

### Revocar una credencial

```bash cURL theme={null}
curl -X DELETE "https://api.matcher.example.com/v1/exceptions/callbacks/credentials/{credentialId}" \
 -H "Authorization: Bearer $TOKEN"
```

La revocación es terminal: la credencial ya no puede autenticar callbacks entrantes.

## Seguridad de webhooks

***

### Verificación de firma

Cuando se configura un secreto compartido de webhook, Matcher firma cada entrega con un HMAC-SHA256 sobre el **cuerpo de la solicitud sin procesar** y lo envía en el encabezado `X-Signature-256`, con el formato `sha256=<hex-digest>`:

```
X-Signature-256: sha256=abc123...
```

Cada entrega también incluye un encabezado `X-Idempotency-Key` para que los receptores puedan deduplicar los reintentos.

**Proceso de verificación:**

1. Calcula el HMAC-SHA256 del cuerpo de la solicitud sin procesar usando el secreto compartido del webhook
2. Antepón `sha256=` al hex digest
3. Compara (en tiempo constante) con el encabezado `X-Signature-256`

**Ejemplo (Node.js):**

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
 const expectedSignature = crypto
 .createHmac('sha256', secret)
 .update(payload)
 .digest('hex');

 return `sha256=${expectedSignature}` === signature;
}
```

**Ejemplo (Python):**

```python theme={null}
import hmac
import hashlib

def verify_webhook(payload, signature, secret):
 expected = hmac.new(
 secret.encode(),
 payload,
 hashlib.sha256
 ).hexdigest()
 return f"sha256={expected}" == signature
```

### Postura de red

Matcher se despliega en tu propia infraestructura, por lo que las entregas de webhooks se originan en el egress de tu despliegue — no hay un rango fijo de IPs de Lerian que permitir. Sirve los endpoints de webhook por HTTPS con un certificado válido. Como protección contra SSRF, Matcher se niega a entregar a direcciones IP privadas o de loopback a menos que el despliegue las permita explícitamente (solo desarrollo).

## Lógica de reintentos

***

Las entregas de webhooks fallidas se reintentan con retroceso exponencial.

### Política de reintentos por defecto

Una entrega fallida se reintenta hasta **3 veces** por defecto. Los retrasos siguen un retroceso exponencial desde una base de **1 segundo**, con jitter añadido para distribuir los reintentos — así el espaciado exacto varía de un intento a otro en lugar de seguir una escala fija.

### Condiciones de reintento

Los reintentos ocurren para:

* Respuestas HTTP 429
* Respuestas HTTP 5xx
* Errores de transporte (fallos de conexión, timeouts)

Sin reintento para:

* Otras respuestas HTTP 4xx

## Mejores prácticas

***

<AccordionGroup>
  <Accordion title="Verifica las firmas de webhooks">
    Verifica siempre la firma HMAC antes de procesar los payloads de webhooks. Esto previene solicitudes falsificadas.
  </Accordion>

  <Accordion title="Responde rápidamente">
    Retorna una respuesta 2xx dentro de 5 segundos. Procesa el evento de forma asíncrona si es necesario.
  </Accordion>

  <Accordion title="Maneja duplicados de forma idempotente">
    Las entregas pueden llegar más de una vez. Deduplica con el encabezado `X-Idempotency-Key` o el `eventId` del payload.
  </Accordion>

  <Accordion title="Monitorea la salud de las entregas">
    Configura alertas para las tasas de falla de webhooks. Investiga las fallas persistentes de inmediato.
  </Accordion>
</AccordionGroup>

## Próximos pasos

***

<Card title="Enrutamiento de excepciones" icon="route" href="/es/matcher/configuration/matcher-exception-routing" horizontal>
  Configura cómo las excepciones activan eventos de webhook.
</Card>

<Card title="Fuentes externas" icon="building-columns" href="/es/matcher/integrations/matcher-external-sources" horizontal>
  Configura fuentes de datos que pueden enviar mediante webhooks.
</Card>
