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

# Matcher events

> Reference the domain events emitted by Lerian Matcher — reconciliation contexts, match runs, exceptions, disputes, and governance — with payloads and delivery semantics.

Matcher emits domain events as **CloudEvents 1.0** messages in binary content mode over Kafka, published through `lib-streaming`. Every event travels in the [shared envelope](/en/reference/events/overview): `ce-type` names the event as `studio.lerian.<resource>.<event>`, `ce-subject` carries the aggregate id, `ce-tenantid` the owning tenant, and `ce-schemaversion` the payload version — `1.0.0` for every event below.

`ce-source` comes from `STREAMING_CLOUDEVENTS_SOURCE` and is required when streaming is enabled; deployments conventionally set `matcher`, so topics land on `matcher.<resource>.<event>` (see [Topic naming](/en/reference/events/overview#topic-naming)). Money amounts — fee values, adjustment amounts — cross the wire as decimal **strings**, never floats. Matcher serves its full event catalog at `GET /system/matcher/streaming/manifest`.

This page covers the Kafka streaming plane. Matcher's exception **webhook** dispatch — HTTP callbacks for exception routing — is a separate surface, documented in [Webhooks and callbacks](/en/matcher/integrations/matcher-webhooks-callbacks).

## Delivery policies

Matcher's catalog uses two delivery policies:

* **Outbox-backed** events are written to the outbox in the same database transaction as the state change; a relay publishes committed rows and retries through broker outages. These are the audit-grade facts (matching outcomes, exception resolutions, disputes, governance). This policy cannot be weakened per deployment.
* **Direct** events publish after the transaction commits, best-effort, falling back to the outbox only when the broker circuit is open. These are configuration and operational lifecycle signals.

Each table below states the policy for its events.

## Matching events

Outbox-backed: `transaction.matched`, `transaction.pending_review`. Direct: the rest.

| Event (`ce-type`)                          | Topic                                | Fires when                                                                                                         | Key payload                                                                                                                                                                                                            |
| ------------------------------------------ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `studio.lerian.transaction.matched`        | `matcher.transaction.matched`        | A transaction line reaches terminal MATCHED in a match-run commit — one event per matched line.                    | `transaction_id`, `context_id`, `match_run_id`, `previous_status`, `status`, `match_group_id`?, `candidate_match_group_id`?, `source_id`?, `matched_at`?                                                               |
| `studio.lerian.transaction.pending_review` | `matcher.transaction.pending_review` | A candidate match needs human review (non-automatic rule).                                                         | Same schema, with `pending_review_at`?                                                                                                                                                                                 |
| `studio.lerian.transaction.ignored`        | `matcher.transaction.ignored`        | A transaction is excluded from matching.                                                                           | `transaction_id`, `ingestion_job_id`, `context_id`, `source_id`, `previous_status`, `status`, `extraction_status`, `updated_at`                                                                                        |
| `studio.lerian.match_run.completed`        | `matcher.match_run.completed`        | A match run finishes. Lender consumes this event to translate reconciliation verdicts into loan servicing actions. | `match_run_id`, `context_id`, `mode`, `status`, `stats`, `started_at`, `completed_at`?                                                                                                                                 |
| `studio.lerian.match_run.failed`           | `matcher.match_run.failed`           | A match run fails.                                                                                                 | As `completed`, plus `failure_reason`                                                                                                                                                                                  |
| `studio.lerian.match_group.confirmed`      | `matcher.match_group.confirmed`      | A match group is confirmed.                                                                                        | `match_group_id`, `match_run_id`, `context_id`, `rule_id`, `transaction_ids`, `confidence`, `status`, `confirmed_at`?                                                                                                  |
| `studio.lerian.match_group.unmatched`      | `matcher.match_group.unmatched`      | A confirmed match group is undone.                                                                                 | As `confirmed`, plus `previous_status`, `reason`, `unmatched_at`                                                                                                                                                       |
| `studio.lerian.fee_variance.created`       | `matcher.fee_variance.created`       | A fee-aware rule detects a variance between expected and actual fees.                                              | `fee_variance_id`, `context_id`, `match_run_id`, `match_group_id`, `transaction_id`, `fee_schedule_id`, `fee_schedule_name_snapshot`, `currency`, `expected_fee`, `actual_fee`, `delta`, `variance_type`, `created_at` |

## Exception and dispute events

Outbox-backed except `exception.assigned` and the comment events, which are direct.

| Event (`ce-type`)                               | Topic                                     | Fires when                                                       | Key payload                                                                                             |
| ----------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `studio.lerian.exception.assigned`              | `matcher.exception.assigned`              | An exception is assigned to an operator.                         | `exception_id`, `status`, `version`, `assigned_at`                                                      |
| `studio.lerian.exception.resolved`              | `matcher.exception.resolved`              | An exception is resolved.                                        | `exception_id`, `status`, `version`, `resolution_type`?, `transaction_id`?, `resolved_at`               |
| `studio.lerian.exception.force_match_resolved`  | `matcher.exception.force_match_resolved`  | An exception is resolved by force-match with an override reason. | Base fields plus `resolution_type` (`FORCE_MATCH`), `override_reason_code`, `resolved_at`               |
| `studio.lerian.exception.adjust_entry_resolved` | `matcher.exception.adjust_entry_resolved` | An exception is resolved by an adjustment entry.                 | Base fields plus `resolution_type` (`ADJUST_ENTRY`), `reason_code`, `amount`, `currency`, `resolved_at` |
| `studio.lerian.exception.dispatched`            | `matcher.exception.dispatched`            | An exception is dispatched to an external system.                | `exception_id`, `target_system`, `queue`, `external_reference`, `acknowledged`, `dispatched_at`         |
| `studio.lerian.exception.callback_processed`    | `matcher.exception.callback_processed`    | An external system's callback is applied to an exception.        | Base fields plus `external_system`, `external_issue_id`, `callback_type`, `processed_at`                |
| `studio.lerian.exception_comment.added`         | `matcher.exception_comment.added`         | A comment is added to an exception thread.                       | `comment_id`, `exception_id`, `created_at`                                                              |
| `studio.lerian.exception_comment.deleted`       | `matcher.exception_comment.deleted`       | A comment is deleted.                                            | `comment_id`, `exception_id`, `actor`, `deleted_at`                                                     |
| `studio.lerian.dispute.opened`                  | `matcher.dispute.opened`                  | A dispute is opened on an exception.                             | `dispute_id`, `exception_id`, `state`, `resolution`?, `category`, `opened_at`                           |
| `studio.lerian.dispute.won`                     | `matcher.dispute.won`                     | A dispute closes as won.                                         | As `opened`, plus `closed_at`                                                                           |
| `studio.lerian.dispute.lost`                    | `matcher.dispute.lost`                    | A dispute closes as lost.                                        | As `opened`, plus `closed_at`                                                                           |
| `studio.lerian.evidence.submitted`              | `matcher.evidence.submitted`              | Evidence is attached to a dispute.                               | `evidence_id`, `dispute_id`, `exception_id`, `has_file`, `submitted_at`                                 |

## Configuration and data-intake events

All direct.

| Event (`ce-type`)                              | Topic                                    | Fires when                                                                | Key payload                                                                                                                                           |
| ---------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `studio.lerian.reconciliation_context.created` | `matcher.reconciliation_context.created` | A reconciliation context is created.                                      | `context_id`, `name`, `context_type`, `interval`, `status`, `auto_match_on_upload`, `created_at`, `tenant_id`                                         |
| `studio.lerian.reconciliation_context.updated` | `matcher.reconciliation_context.updated` | A context's metadata or lifecycle status changes.                         | Same schema, with `updated_at`                                                                                                                        |
| `studio.lerian.reconciliation_source.created`  | `matcher.reconciliation_source.created`  | A source (input side) is created in a context.                            | `context_id`, `source_id`, `name`, `source_type`, `side`, `created_at`                                                                                |
| `studio.lerian.match_rule.created`             | `matcher.match_rule.created`             | A match rule is created.                                                  | `context_id`, `rule_id`, `rule_type`, `priority`, `config_hash`, `created_at`                                                                         |
| `studio.lerian.match_rule.reordered`           | `matcher.match_rule.reordered`           | Rule priorities are reordered.                                            | `context_id`, `ordered_rule_ids`, `priority_version`, `reordered_at`                                                                                  |
| `studio.lerian.fetcher_connection.synced`      | `matcher.fetcher_connection.synced`      | A Fetcher connection and its discovered schema snapshot are synchronized. | `connection_id`, `fetcher_connection_id`, `config_name`, `database_type`, `status`, `schema_discovered`, `last_seen_at`, `updated_at`                 |
| `studio.lerian.fetcher_connection.unreachable` | `matcher.fetcher_connection.unreachable` | A Fetcher connection becomes unreachable.                                 | Same schema, plus `previous_status`                                                                                                                   |
| `studio.lerian.extraction_request.created`     | `matcher.extraction_request.created`     | An extraction request is created against a connection.                    | `extraction_request_id`, `connection_id`, `status`, `table_count`, `has_filters`, `start_date`, `end_date`, `created_at`                              |
| `studio.lerian.ingestion.completed`            | `matcher.ingestion.completed`            | An ingestion job completes.                                               | `job_id`, `context_id`, `source_id`, `status`, `total_rows`, `failed_rows`, `transaction_count`, `date_range_start`, `date_range_end`, `completed_at` |
| `studio.lerian.ingestion.failed`               | `matcher.ingestion.failed`               | An ingestion job fails.                                                   | `job_id`, `context_id`, `source_id`, `status`, `total_rows`, `failed_rows`, `error_code`, `failed_at`                                                 |

## Governance and reporting events

Outbox-backed except the export-job family, which is direct.

| Event (`ce-type`)                        | Topic                              | Fires when                                             | Key payload                                                                                                                                                                                                                  |
| ---------------------------------------- | ---------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `studio.lerian.audit_log.created`        | `matcher.audit_log.created`        | A hash-chained audit log entry is persisted.           | `audit_log_id`, `tenant_id`, `entity_type`, `entity_id`, `action`, `tenant_seq`, `hash_version`, `record_hash`, `created_at`                                                                                                 |
| `studio.lerian.archive_metadata.created` | `matcher.archive_metadata.created` | The archival worker registers an archive partition.    | `archive_metadata_id`, `tenant_id`, `partition_name`, `date_range_start`, `date_range_end`, `status`, `created_at`, `updated_at`, plus `checksum`?, `row_count`?, `compressed_size_bytes`?, `storage_class`?, `archived_at`? |
| `studio.lerian.archive.uploaded`         | `matcher.archive.uploaded`         | An archive is uploaded to storage.                     | Same schema                                                                                                                                                                                                                  |
| `studio.lerian.archive.completed`        | `matcher.archive.completed`        | An archival cycle completes.                           | Same schema                                                                                                                                                                                                                  |
| `studio.lerian.actor.pseudonymized`      | `matcher.actor.pseudonymized`      | An actor's personal data is pseudonymized (GDPR/LGPD). | `actor_id`, `pseudonymized`, `display_name_status`, `email_status`, `updated_at`, `tenant_id`                                                                                                                                |
| `studio.lerian.export_job.created`       | `matcher.export_job.created`       | An export job is created.                              | `export_job_id`, `tenant_id`, `context_id`, `report_type`, `format`, `status`, `schema_version`, `created_at`, `expires_at`, `updated_at`                                                                                    |
| `studio.lerian.export_job.succeeded`     | `matcher.export_job.succeeded`     | An export job finishes writing its artifact.           | Same schema, plus `file_name`?, `sha256`?, `records_written`?, `bytes_written`?, `attempts`?, `finished_at`?                                                                                                                 |
| `studio.lerian.export_job.failed`        | `matcher.export_job.failed`        | An export job fails.                                   | Same schema, plus `error_code`, `attempts`?, `finished_at`?                                                                                                                                                                  |
| `studio.lerian.export_job.expired`       | `matcher.export_job.expired`       | An export artifact expires and is cleaned up.          | Same schema, plus `expired_at`?                                                                                                                                                                                              |

## Declared but not yet emitted

The catalog and manifest declare seven additional events that **no code path emits today**: `reconciliation_context.deleted` and the `extraction_request` lifecycle family (`submitted`, `completed`, `failed`, `cancelled`, `bridged`, `bridge_failed`). They are contract reservations — do not build consumers that depend on receiving them.

## Events consumed

Matcher consumes **no Kafka streaming events**. Its integration inputs arrive over HTTP: file uploads, Fetcher extractions, and — when enabled — Streaming Hub webhook deliveries on `POST /v1/discovery/hub/events` (HMAC-signed, deduplicated by event id, disabled by default).
