> ## 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**: Matcher notifica a los sistemas externos cuando ocurren eventos
* **Callbacks entrantes**: los sistemas externos notifican a Matcher cuando se toman acciones

Cuando algo sucede en Matcher, como una nueva excepción o una coincidencia completada, envía un evento a tus endpoints configurados. 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.

<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.

### Eventos disponibles

El catálogo de eventos de Matcher se define de forma centralizada (46 eventos en la v4.1.0). 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 |

### Estructura del payload de eventos

Todos los eventos siguen una estructura consistente:

```json theme={null}
{
 "id": "evt_001",
 "type": "exception.assigned",
 "timestamp": "2024-01-20T10:30:00Z",
 "version": "1.0",
 "tenant_id": "tenant_001",
 "context_id": "ctx_abc123",
 "data": {
 // Event-specific data
 },
 "metadata": {
 "correlation_id": "req_xyz789",
 "source": "matching_engine"
 }
}
```

## Payloads de eventos

***

### Ingestioncompleted

Se dispara cuando un lote de transacciones se importa exitosamente.

```json theme={null}
{
  "id": "evt_ing_001",
  "type": "ingestion.completed",
  "timestamp": "2024-01-20T10:30:00Z",
  "data": {
    "job_id": "job_imp_001",
    "source_id": "src_bank456",
    "source_name": "Chase Bank",
    "file_name": "statement_january.csv",
    "summary": {
      "total_rows": 1250,
      "imported": 1240,
      "duplicates_skipped": 8,
      "validation_errors": 2
    },
    "duration_seconds": 45,
    "started_at": "2024-01-20T10:29:15Z",
    "completed_at": "2024-01-20T10:30:00Z"
  }
}
```

### Matchconfirmed

Se dispara cuando una coincidencia es aprobada (automática o manual).

```json theme={null}
{
  "id": "evt_mtch_001",
  "type": "match_group.confirmed",
  "timestamp": "2024-01-20T10:30:01Z",
  "data": {
    "match_id": "match_001",
    "confidence": 100,
    "rule_id": "rule_exact001",
    "rule_name": "Exact Match",
    "confirmation_type": "AUTO",
    "transactions": [
      {
        "id": "txn_bank_001",
        "source_name": "Chase Bank",
        "amount": 1000.0,
        "currency": "USD",
        "date": "2024-01-15"
      },
      {
        "id": "txn_ledger_001",
        "source_name": "Main Ledger",
        "amount": 1000.0,
        "currency": "USD",
        "date": "2024-01-15"
      }
    ],
    "variance": {
      "amount_diff": 0,
      "date_diff_days": 0
    }
  }
}
```

### Exceptionresolved

Se dispara cuando una excepción es resuelta.

```json theme={null}
{
  "id": "evt_exc_002",
  "type": "exception.resolved",
  "timestamp": "2024-01-20T14:30:00Z",
  "data": {
    "exception_id": "exc_001",
    "resolution": {
      "type": "FORCE_MATCH",
      "match_id": "match_forced_001",
      "resolved_by": "user_123",
      "notes": "Verified: amount difference is bank wire fee"
    },
    "time_to_resolution": {
      "hours": 4,
      "within_sla": true
    }
  }
}
```

### Matchforcematched

Se dispara cuando un usuario fuerza manualmente una coincidencia entre transacciones.

```json theme={null}
{
  "id": "evt_force_001",
  "type": "exception.force_match_resolved",
  "timestamp": "2024-01-20T14:30:00Z",
  "data": {
    "match_id": "match_forced_001",
    "exception_id": "exc_001",
    "forced_by": "user_123",
    "reason": "Amount difference is documented bank fee",
    "notes": "Verified with bank statement showing $250 wire fee deducted",
    "transactions": [
      {
        "id": "txn_bank_999",
        "source_name": "Chase Bank",
        "amount": 15000.0,
        "currency": "USD",
        "date": "2024-01-15"
      },
      {
        "id": "txn_ledger_777",
        "source_name": "Main Ledger",
        "amount": 15250.0,
        "currency": "USD",
        "date": "2024-01-14"
      }
    ],
    "variance": {
      "amount_diff": 250.0,
      "amount_variance_percent": 1.67,
      "date_diff_days": 1
    },
    "requires_approval": true,
    "approval_threshold": 10000.0
  }
}
```

<Note>
  Los eventos de coincidencia forzada se usan comúnmente para activar flujos de aprobación cuando la variación excede los umbrales de la empresa.
</Note>

### Matchunmatched

Se dispara cuando una coincidencia previamente confirmada es revertida.

```json theme={null}
{
  "id": "evt_unmatch_001",
  "type": "match_group.unmatched",
  "timestamp": "2024-01-20T15:45:00Z",
  "data": {
    "match_id": "match_001",
    "unmatched_by": "user_456",
    "reason": "Incorrect match - transactions belong to different invoices",
    "notes": "Bank txn is for Invoice #1234, ledger txn is for Invoice #5678",
    "original_match": {
      "confirmed_at": "2024-01-15T10:00:00Z",
      "confirmed_by": "system",
      "confidence": 85,
      "rule_name": "Tolerance Match"
    },
    "transactions": [
      {
        "id": "txn_bank_001",
        "source_name": "Chase Bank",
        "amount": 1000.0,
        "currency": "USD"
      },
      {
        "id": "txn_ledger_001",
        "source_name": "Main Ledger",
        "amount": 1005.0,
        "currency": "USD"
      }
    ],
    "action": {
      "exceptions_created": [
        "exc_new_001",
        "exc_new_002"
      ],
      "status": "Both transactions returned to unmatched pool"
    }
  }
}
```

<Warning>
  Deshacer una coincidencia confirmada crea nuevas excepciones para ambas transacciones y genera una entrada completa en el registro de auditoría.
</Warning>

### Matchruncompleted

Se dispara cuando una ejecución de coincidencias automática o manual finaliza.

```json theme={null}
{
  "id": "evt_run_001",
  "type": "match_run.completed",
  "timestamp": "2024-01-20T06:05:23Z",
  "data": {
    "run_id": "run_001",
    "context_id": "ctx_abc123",
    "context_name": "Daily Bank Reconciliation",
    "trigger": "SCHEDULED",
    "started_at": "2024-01-20T06:00:00Z",
    "completed_at": "2024-01-20T06:05:23Z",
    "duration_seconds": 323,
    "statistics": {
      "transactions_processed": 1250,
      "matches_found": 1180,
      "matches_confirmed": 1120,
      "matches_pending_review": 60,
      "exceptions_created": 70,
      "by_confidence": {
        "high_90_100": 1120,
        "medium_60_89": 60,
        "low_0_59": 0
      }
    },
    "performance": {
      "transactions_per_second": 3.87,
      "avg_rule_evaluation_ms": 12.5
    }
  }
}
```

## 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

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/exceptions/{exceptionId}/callback" \
 -H "Authorization: Bearer $TOKEN" \
 -H "X-Idempotency-Key: callback-jira-1234" \
 -H "Content-Type: application/json" \
 -d '{
   "externalSystem": "JIRA",
   "externalIssueId": "RECON-1234",
   "status": "RESOLVED",
   "resolutionNotes": "Verified: amount difference is expected bank wire fee",
   "assignee": "john.doe@company.com"
 }'
```

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.

#### 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
```

### Lista de IPs permitidas

Matcher envía webhooks desde rangos de IP específicos:

```
52.1.2.0/24
52.1.3.0/24
```

Configura tu firewall para permitir estos rangos.

### Requisitos de TLS

* Mínimo TLS 1.2
* Se requiere certificado SSL válido
* Certificados autofirmados no soportados en producción

## 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 5xx
* Timeouts de conexión
* Fallos de resolución DNS

Sin reintento para:

* Respuestas HTTP 4xx (excepto 429)
* Certificados SSL inválidos
* Webhook deshabilitado

## 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">
    Los eventos pueden entregarse más de una vez. Usa el ID del evento para deduplicar.
  </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>

  <Accordion title="Usa filtros de eventos">
    Suscríbete solo a los eventos que necesitas. El filtrado reduce el ruido y la carga de procesamiento.
  </Accordion>

  <Accordion title="Prueba antes de producción">
    Usa el endpoint de prueba para verificar que tu manejador de webhooks funciona correctamente antes de habilitarlo en producción.
  </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>
