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

# Eventos do Matcher

> Referência dos eventos de domínio emitidos pelo Lerian Matcher (contextos de conciliação, execuções de match, exceções, disputas e governança) com payloads e semânticas de entrega.

O catálogo do Matcher tem 42 definições de evento, e o Matcher emite todas elas. Ele emite eventos de domínio como mensagens CloudEvents 1.0 em modo binário de conteúdo. Todo evento trafega no [envelope compartilhado](https://docs.lerian.studio/pt/reference/events/overview.md): `ce-type` nomeia o evento como `studio.lerian.matcher.<resource>.<event>`, `ce-subject` carrega o id do agregado, `ce-tenantid` o tenant proprietário, e `ce-schemaversion` a versão do payload. A versão é `1.0.0` para todo evento abaixo.

`ce-source` é `matcher`. Todo evento usa o tópico de aplicação `lerian.streaming.matcher` e os tipos qualificados por source mostrados abaixo. O tipo de recurso, o tipo de evento e a versão do schema permanecem nos headers do CloudEvents. Valores monetários (valores de tarifa e valores de ajuste) trafegam no wire como strings decimais, nunca como floats.

Os callbacks de resolução de entrada são uma superfície HTTP separada, documentada em [Webhooks e callbacks](https://docs.lerian.studio/pt/products/matcher/integrations/matcher-webhooks-callbacks.md#inbound-callbacks).

## Políticas de entrega

O catálogo do Matcher usa duas políticas de entrega: 16 definições usam a política apoiada em outbox e 26 definições usam entrega direta com fallback de circuit-open.

* **Eventos apoiados em outbox** vão para o outbox na mesma transação de banco de dados que a mudança de estado. Um relay publica as linhas commitadas e faz novas tentativas durante interrupções do broker. Esses são os fatos de nível de auditoria (resultados de correspondência, resoluções de exceção, disputas, governança). Um deploy não pode enfraquecer essa política.
* **Eventos diretos** são publicados depois que a transação faz commit, em regime de melhor esforço, com fallback para o outbox apenas quando o circuit está aberto. Esses são sinais de configuração e de ciclo de vida operacional.

Cada tabela abaixo indica a política de seus eventos.

## Eventos de correspondência

Apoiados em outbox: `transaction.matched`, `transaction.pending_review`. Diretos: os demais.

| Evento (`ce-type`) | Tópico | Dispara quando | Payload principal |
| - | - | - | - |
| `studio.lerian.matcher.transaction.matched` | `lerian.streaming.matcher` | Uma linha de transação alcança o estado terminal MATCHED em um commit de execução de match (um evento por linha correspondida). | `transaction_id`, `context_id`, `match_run_id`, `previous_status`, `status`, `match_group_id`?, `candidate_match_group_id`?, `source_id`?, `matched_at` |
| `studio.lerian.matcher.transaction.pending_review` | `lerian.streaming.matcher` | Uma correspondência candidata precisa de revisão humana (regra não automática). | Mesmo schema, com `pending_review_at` obrigatório |
| `studio.lerian.matcher.transaction.ignored` | `lerian.streaming.matcher` | Uma transação é excluída da correspondência. | `transaction_id`, `ingestion_job_id`, `context_id`, `source_id`, `previous_status`, `status`, `extraction_status`, `updated_at` |
| `studio.lerian.matcher.match_run.completed` | `lerian.streaming.matcher` | Uma execução de match termina. | `match_run_id`, `context_id`, `mode`, `status`, `stats`, `started_at`, `completed_at`? |
| `studio.lerian.matcher.match_run.failed` | `lerian.streaming.matcher` | Uma execução de match falha. | `match_run_id`, `context_id`, `mode`, `status`, `failure_reason`, `started_at`, `completed_at`? |
| `studio.lerian.matcher.match_group.confirmed` | `lerian.streaming.matcher` | Um grupo de correspondência é confirmado. | `match_group_id`, `match_run_id`, `context_id`, `rule_id`, `transaction_ids`, `confidence`, `status`, `confirmed_at`? |
| `studio.lerian.matcher.match_group.unmatched` | `lerian.streaming.matcher` | Um grupo de correspondência confirmado é desfeito. | `match_group_id`, `match_run_id`, `context_id`, `rule_id`, `transaction_ids`, `previous_status`, `status`, `reason`, `unmatched_at` |
| `studio.lerian.matcher.fee_variance.created` | `lerian.streaming.matcher` | Uma regra sensível a tarifas detecta uma variação entre a tarifa esperada e a real. | `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` |

## Eventos de exceção e disputa

Apoiados em outbox, exceto `exception.assigned` e os eventos de comentário, que são diretos.

| Evento (`ce-type`) | Tópico | Dispara quando | Payload principal |
| - | - | - | - |
| `studio.lerian.matcher.exception.assigned` | `lerian.streaming.matcher` | Uma exceção é atribuída a um operador. | `exception_id`, `status`, `version`, `resolution_type`?, `transaction_id`?, `assigned_at` |
| `studio.lerian.matcher.exception.resolved` | `lerian.streaming.matcher` | Uma exceção é resolvida pela operação de resolução individual ou em lote. | `exception_id`, `status`, `version`, `resolution_type`?, `transaction_id`?, `resolved_at` |
| `studio.lerian.matcher.exception.force_match_resolved` | `lerian.streaming.matcher` | Uma exceção é resolvida por correspondência forçada, com um motivo de substituição. | Campos base mais `resolution_type` (`FORCE_MATCH`), `override_reason_code`, `resolved_at` |
| `studio.lerian.matcher.exception.adjust_entry_resolved` | `lerian.streaming.matcher` | Uma exceção é resolvida por um lançamento de ajuste. | Campos base mais `resolution_type` (`ADJUST_ENTRY`), `reason_code`, `amount`, `currency`, `resolved_at` |
| `studio.lerian.matcher.exception.dispatched` | `lerian.streaming.matcher` | Uma exceção é despachada. | `exception_id`, `target_system`, `queue`, `external_reference`, `acknowledged`, `dispatched_at` |
| `studio.lerian.matcher.exception.callback_processed` | `lerian.streaming.matcher` | O callback de um sistema externo é aplicado a uma exceção. | Campos base mais `external_system`, `external_issue_id`, `callback_type`, `processed_at` |
| `studio.lerian.matcher.exception_comment.added` | `lerian.streaming.matcher` | Um comentário é adicionado a uma thread de exceção. | `comment_id`, `exception_id`, `created_at` |
| `studio.lerian.matcher.exception_comment.deleted` | `lerian.streaming.matcher` | Um comentário é excluído. | `comment_id`, `exception_id`, `actor`, `deleted_at` |
| `studio.lerian.matcher.dispute.opened` | `lerian.streaming.matcher` | Uma disputa é aberta em uma exceção. | `dispute_id`, `exception_id`, `state`, `resolution`?, `category`, `opened_at` |
| `studio.lerian.matcher.dispute.won` | `lerian.streaming.matcher` | Uma disputa é encerrada como ganha. | `dispute_id`, `exception_id`, `state`, `resolution`?, `closed_at` |
| `studio.lerian.matcher.dispute.lost` | `lerian.streaming.matcher` | Uma disputa é encerrada como perdida. | `dispute_id`, `exception_id`, `state`, `resolution`?, `closed_at` |
| `studio.lerian.matcher.evidence.submitted` | `lerian.streaming.matcher` | Uma evidência é anexada a uma disputa. | `evidence_id`, `dispute_id`, `exception_id`, `has_file`, `submitted_at` |

## Eventos de configuração e entrada de dados

Todos diretos.

| Evento (`ce-type`) | Tópico | Dispara quando | Payload principal |
| - | - | - | - |
| `studio.lerian.matcher.reconciliation_context.created` | `lerian.streaming.matcher` | Um contexto de conciliação é criado. | `context_id`, `name`, `context_type`, `interval`, `status`, `auto_match_on_upload`, `created_at`, `tenant_id` |
| `studio.lerian.matcher.reconciliation_context.updated` | `lerian.streaming.matcher` | Os metadados ou o status de ciclo de vida de um contexto mudam. | `context_id`, `name`, `context_type`, `interval`, `status`, `auto_match_on_upload`, `updated_at`, `tenant_id` |
| `studio.lerian.matcher.reconciliation_source.created` | `lerian.streaming.matcher` | Uma fonte (lado de entrada) é criada em um contexto. | `context_id`, `source_id`, `name`, `source_type`, `side`, `created_at`, `tenant_id` |
| `studio.lerian.matcher.match_rule.created` | `lerian.streaming.matcher` | Uma regra de correspondência é criada. | `context_id`, `rule_id`, `rule_type`, `priority`, `config_hash`, `created_at`, `tenant_id` |
| `studio.lerian.matcher.match_rule.reordered` | `lerian.streaming.matcher` | As prioridades das regras são reordenadas. | `context_id`, `ordered_rule_ids`, `priority_version`, `reordered_at`, `tenant_id` |
| `studio.lerian.matcher.fetcher_connection.synced` | `lerian.streaming.matcher` | Uma conexão do Discovery e o snapshot do schema descoberto são sincronizados. | `connection_id`, `fetcher_connection_id`, `config_name`, `database_type`, `status`, `schema_discovered`, `last_seen_at`, `updated_at` |
| `studio.lerian.matcher.fetcher_connection.unreachable` | `lerian.streaming.matcher` | Uma conexão do Discovery fica inacessível. | `connection_id`, `fetcher_connection_id`, `previous_status`, `status`, `schema_discovered`, `updated_at` |
| `studio.lerian.matcher.extraction_request.created` | `lerian.streaming.matcher` | Uma requisição de extração é criada para uma conexão. | `extraction_request_id`, `connection_id`, `status`, `table_count`, `has_filters`, `start_date`, `end_date`, `created_at` |
| `studio.lerian.matcher.extraction_request.submitted` | `lerian.streaming.matcher` | O motor de extração embutido do Matcher aceita uma requisição de extração. | `extraction_request_id`, `connection_id`, `status` |
| `studio.lerian.matcher.extraction_request.completed` | `lerian.streaming.matcher` | Uma requisição de extração é concluída depois que o Matcher entrega os dados dela à ingestão. | Mesmo schema |
| `studio.lerian.matcher.extraction_request.failed` | `lerian.streaming.matcher` | Uma requisição de extração falha. | Mesmo schema, mais `error_code` |
| `studio.lerian.matcher.ingestion.completed` | `lerian.streaming.matcher` | Um job de ingestão é concluído. | `job_id`, `context_id`, `source_id`, `status`, `total_rows`, `failed_rows`, `transaction_count`, `date_range_start`?, `date_range_end`?, `completed_at`?, `error_code`? |
| `studio.lerian.matcher.ingestion.failed` | `lerian.streaming.matcher` | Um job de ingestão falha. | `job_id`, `context_id`, `source_id`, `status`, `total_rows`, `failed_rows`, `error_code`?, `failed_at`? |

## Eventos de governança e relatórios

Apoiados em outbox, exceto a família export-job, que é direta.

| Evento (`ce-type`) | Tópico | Dispara quando | Payload principal |
| - | - | - | - |
| `studio.lerian.matcher.audit_log.created` | `lerian.streaming.matcher` | Uma entrada de log de auditoria encadeada por hash é persistida. | `audit_log_id`, `tenant_id`, `entity_type`, `entity_id`, `action`, `tenant_seq`, `hash_version`, `record_hash`, `created_at` |
| `studio.lerian.matcher.archive_metadata.created` | `lerian.streaming.matcher` | O worker de arquivamento registra uma partição de arquivo. | `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.matcher.archive.uploaded` | `lerian.streaming.matcher` | Um arquivo é enviado para o armazenamento. | Mesmo schema |
| `studio.lerian.matcher.archive.completed` | `lerian.streaming.matcher` | Um ciclo de arquivamento é concluído. | Mesmo schema |
| `studio.lerian.matcher.actor.pseudonymized` | `lerian.streaming.matcher` | Os dados pessoais de um ator são pseudonimizados (GDPR/LGPD). | `actor_id`, `pseudonymized`, `display_name_status`, `email_status`, `updated_at`, `tenant_id` |
| `studio.lerian.matcher.export_job.created` | `lerian.streaming.matcher` | Um job de exportação é criado. | `export_job_id`, `tenant_id`, `context_id`, `report_type`, `format`, `status`, `schema_version`, `created_at`, `expires_at`, `updated_at` |
| `studio.lerian.matcher.export_job.succeeded` | `lerian.streaming.matcher` | Um job de exportação termina de gravar seu artefato. | Mesmo schema, mais `file_name`?, `sha256`?, `records_written`?, `bytes_written`?, `attempts`?, `finished_at`? |
| `studio.lerian.matcher.export_job.failed` | `lerian.streaming.matcher` | Um job de exportação falha. | Mesmo schema, mais `error_code`?, `attempts`?, `finished_at`? |
| `studio.lerian.matcher.export_job.expired` | `lerian.streaming.matcher` | Um artefato de exportação expira e é limpo. | Mesmo schema, mais `expired_at`? |

## Contratos de payload

Esses tipos espelham os objetos `data` do CloudEvent emitidos pelo Matcher. `?` significa que a propriedade pode estar ausente. Os timestamps são UTC RFC 3339 com precisão de nanossegundos. Os aliases de UUID documentam identidade semântica. Um campo tipado como `string` não carrega garantia de UUID. `stats` é um mapa de inteiros aberto, então os consumidores devem tolerar novas chaves.

```typescript theme={null}
type RFC3339Nano = string
type DecimalString = string
type UUID = string
type MatchRunStats = Record<string, number>

// reconciliation_context.created
type ReconciliationContextCreatedDataV1 = {
  context_id: UUID
  name: string
  context_type: string
  interval: string
  status: string
  auto_match_on_upload: boolean
  created_at: RFC3339Nano
  tenant_id: string
}

// reconciliation_context.updated
type ReconciliationContextUpdatedDataV1 = {
  context_id: UUID
  name: string
  context_type: string
  interval: string
  status: string
  auto_match_on_upload: boolean
  updated_at: RFC3339Nano
  tenant_id: string
}

// reconciliation_source.created
type ReconciliationSourceCreatedDataV1 = {
  context_id: UUID
  source_id: UUID
  name: string
  source_type: string
  side: string
  created_at: RFC3339Nano
  tenant_id: string
}

// match_rule.created
type MatchRuleCreatedDataV1 = {
  context_id: UUID
  rule_id: UUID
  rule_type: string
  priority: number
  config_hash: string
  created_at: RFC3339Nano
  tenant_id: string
}

// match_rule.reordered
type MatchRuleReorderedDataV1 = {
  context_id: UUID
  ordered_rule_ids: UUID[]
  priority_version: string
  reordered_at: RFC3339Nano
  tenant_id: string
}

// fetcher_connection.synced
type FetcherConnectionSyncedDataV1 = {
  connection_id: UUID
  fetcher_connection_id: string
  config_name: string
  database_type: string
  status: string
  schema_discovered: boolean
  last_seen_at: RFC3339Nano
  updated_at: RFC3339Nano
}

// fetcher_connection.unreachable
type FetcherConnectionUnreachableDataV1 = {
  connection_id: UUID
  fetcher_connection_id: string
  previous_status: string
  status: string
  schema_discovered: boolean
  updated_at: RFC3339Nano
}

// extraction_request.created
type ExtractionRequestCreatedDataV1 = {
  extraction_request_id: UUID
  connection_id: UUID
  status: string
  table_count: number
  has_filters: boolean
  start_date: string
  end_date: string
  created_at: RFC3339Nano
}

// extraction_request.submitted, extraction_request.completed, and extraction_request.failed
type ExtractionRequestLifecycleDataV1 = {
  extraction_request_id: UUID
  connection_id: UUID
  status: string
  error_code?: "EXTRACTION_REQUEST_FAILED"
}

// ingestion.completed
type IngestionCompletedDataV1 = {
  job_id: UUID
  context_id: UUID
  source_id: UUID
  status: string
  total_rows: number
  failed_rows: number
  transaction_count: number
  date_range_start?: RFC3339Nano
  date_range_end?: RFC3339Nano
  completed_at?: RFC3339Nano
  error_code?: string
}

// ingestion.failed
type IngestionFailedDataV1 = {
  job_id: UUID
  context_id: UUID
  source_id: UUID
  status: string
  total_rows: number
  failed_rows: number
  failed_at?: RFC3339Nano
  error_code?: string
}

// transaction.ignored
type TransactionIgnoredDataV1 = {
  transaction_id: UUID
  ingestion_job_id: UUID
  context_id: UUID
  source_id: UUID
  previous_status: string
  status: string
  extraction_status: string
  updated_at: RFC3339Nano
}

// transaction.matched
type TransactionMatchedDataV1 = {
  transaction_id: UUID
  context_id: UUID
  match_run_id: UUID
  previous_status: string
  status: string
  match_group_id?: UUID
  candidate_match_group_id?: UUID
  source_id?: UUID
  matched_at: RFC3339Nano
}

// transaction.pending_review
type TransactionPendingReviewDataV1 = {
  transaction_id: UUID
  context_id: UUID
  match_run_id: UUID
  previous_status: string
  status: string
  match_group_id?: UUID
  candidate_match_group_id?: UUID
  source_id?: UUID
  pending_review_at: RFC3339Nano
}

// match_run.completed
type MatchRunCompletedDataV1 = {
  match_run_id: UUID
  context_id: UUID
  mode: string
  status: string
  stats: MatchRunStats
  started_at: RFC3339Nano
  completed_at?: RFC3339Nano
}

// match_run.failed
type MatchRunFailedDataV1 = {
  match_run_id: UUID
  context_id: UUID
  mode: string
  status: string
  failure_reason: string
  started_at: RFC3339Nano
  completed_at?: RFC3339Nano
}

// match_group.confirmed
type MatchGroupConfirmedDataV1 = {
  match_group_id: UUID
  match_run_id: UUID
  context_id: UUID
  rule_id: UUID
  transaction_ids: UUID[]
  confidence: number
  status: string
  confirmed_at?: RFC3339Nano
}

// match_group.unmatched
type MatchGroupUnmatchedDataV1 = {
  match_group_id: UUID
  match_run_id: UUID
  context_id: UUID
  rule_id: UUID
  transaction_ids: UUID[]
  previous_status: string
  status: string
  reason: string
  unmatched_at: RFC3339Nano
}

// fee_variance.created
type FeeVarianceCreatedDataV1 = {
  fee_variance_id: UUID
  context_id: UUID
  match_run_id: UUID
  match_group_id: UUID
  transaction_id: UUID
  fee_schedule_id: UUID
  fee_schedule_name_snapshot: string
  currency: string
  expected_fee: DecimalString
  actual_fee: DecimalString
  delta: DecimalString
  variance_type: string
  created_at: RFC3339Nano
}

type ExceptionDataBaseV1 = {
  exception_id: UUID
  status: string
  version: number
  resolution_type?: string
  transaction_id?: UUID
}

// exception.assigned
type ExceptionAssignedDataV1 = ExceptionDataBaseV1 & {
  assigned_at: RFC3339Nano
}

// exception.resolved
type ExceptionResolvedDataV1 = ExceptionDataBaseV1 & {
  resolved_at: RFC3339Nano
}

// exception.callback_processed
type ExceptionCallbackProcessedDataV1 = ExceptionDataBaseV1 & {
  external_system: string
  external_issue_id: string
  callback_type: string
  processed_at: RFC3339Nano
}

// exception.force_match_resolved
type ExceptionForceMatchResolvedDataV1 = ExceptionDataBaseV1 & {
  resolution_type: "FORCE_MATCH"
  override_reason_code: string
  resolved_at: RFC3339Nano
}

// exception.adjust_entry_resolved
type ExceptionAdjustEntryResolvedDataV1 = ExceptionDataBaseV1 & {
  resolution_type: "ADJUST_ENTRY"
  reason_code: string
  amount: DecimalString
  currency: string
  resolved_at: RFC3339Nano
}

// exception.dispatched
type ExceptionDispatchedDataV1 = {
  exception_id: UUID
  target_system: string
  queue: string
  external_reference: string
  acknowledged: boolean
  dispatched_at: RFC3339Nano
}

// exception_comment.added
type ExceptionCommentAddedDataV1 = {
  comment_id: UUID
  exception_id: UUID
  created_at: RFC3339Nano
}

// exception_comment.deleted
type ExceptionCommentDeletedDataV1 = {
  comment_id: UUID
  exception_id: UUID
  actor: string
  deleted_at: RFC3339Nano
}

// dispute.opened
type DisputeOpenedDataV1 = {
  dispute_id: UUID
  exception_id: UUID
  state: string
  resolution?: string
  category: string
  opened_at: RFC3339Nano
}

// dispute.won and dispute.lost
type DisputeClosedDataV1 = {
  dispute_id: UUID
  exception_id: UUID
  state: string
  resolution?: string
  closed_at: RFC3339Nano
}

// evidence.submitted
type EvidenceSubmittedDataV1 = {
  evidence_id: UUID
  dispute_id: UUID
  exception_id: UUID
  has_file: boolean
  submitted_at: RFC3339Nano
}

// audit_log.created
type AuditLogCreatedDataV1 = {
  audit_log_id: UUID
  tenant_id: UUID
  entity_type: string
  entity_id: UUID
  action: string
  tenant_seq: number
  hash_version: number
  record_hash: string
  created_at: RFC3339Nano
}

// archive_metadata.created, archive.uploaded, and archive.completed
type ArchiveDataV1 = {
  archive_metadata_id: UUID
  tenant_id: UUID
  partition_name: string
  date_range_start: RFC3339Nano
  date_range_end: RFC3339Nano
  status: string
  created_at: RFC3339Nano
  updated_at: RFC3339Nano
  checksum?: string
  row_count?: number
  compressed_size_bytes?: number
  storage_class?: string
  archived_at?: RFC3339Nano
}

// actor.pseudonymized
type ActorPseudonymizedDataV1 = {
  actor_id: string
  pseudonymized: boolean
  display_name_status: "REDACTED"
  email_status: "REDACTED"
  updated_at: RFC3339Nano
  tenant_id: string
}

// export_job.created, export_job.succeeded, export_job.failed, and export_job.expired
type ExportJobDataV1 = {
  export_job_id: UUID
  tenant_id: UUID
  context_id: UUID
  report_type: string
  format: string
  status: string
  schema_version: "1.0.0"
  created_at: RFC3339Nano
  expires_at: RFC3339Nano
  updated_at: RFC3339Nano
  file_name?: string
  sha256?: string
  records_written?: number
  bytes_written?: number
  attempts?: number
  error_code?: "EXPORT_JOB_FAILED"
  finished_at?: RFC3339Nano
  expired_at?: RFC3339Nano
}
```

`ingestion.completed` inclui o intervalo de datas apenas quando o pipeline o calcula. Os timestamps terminais e os códigos de erro estáveis dependem do agregado persistido. Os contadores de exportação ficam ausentes enquanto forem zero. `dispute.won` e `dispute.lost` não repetem a `category` enviada por `dispute.opened`.

## Eventos consumidos

O Matcher não consome nenhum evento de streaming. Suas entradas de integração chegam via HTTP, como envios de arquivo e extrações do Discovery.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.