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

# Revisões de extração

> Revise, aprove ou rejeite candidatos de transações extraídos por IA antes de serem ingeridos, e use propostas de mapeamento e ações de job para preparar os dados de origem.

O Matcher pode extrair candidatos de transações de documentos e propor mapeamentos de campos usando IA — mas **a saída da IA nunca é autoritativa**. Nada é conciliado até que um humano aprove. Este guia cobre a fila de revisão de extração com supervisão humana (HITL), as propostas de mapeamento de IA e as ações de job relacionadas.

<Note>A esteira de extração de documentos é protegida por um kill-switch global **e** uma adesão explícita por tenant. Um tenant que não aderiu recebe `403` antes que qualquer byte do documento seja armazenado ou transmitido.</Note>

## Enfileirar um documento para extração

***

Faça upload de um documento de origem (PDF) para executar a extração determinística + IA. Os candidatos de transações resultantes são enfileirados em uma revisão — nada é conciliado ainda.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/imports/contexts/{contextId}/sources/{sourceId}/extract-document" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @statement.pdf
```

A resposta (`202 Accepted`) retorna o id da revisão enfileirada, a contagem de candidatos e um status que é sempre `PENDING_REVIEW` ao enfileirar:

```json theme={null}
{
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "candidateCount": 12,
  "status": "PENDING_REVIEW"
}
```

## A fila de revisão

***

### Listar revisões

Lista paginada por cursor das revisões de extração de um contexto, opcionalmente filtrada por status do ciclo de vida.

```bash theme={null}
curl -X GET "https://api.matcher.example.com/v1/imports/contexts/{contextId}/extraction-reviews?status=PENDING_REVIEW&limit=50" \
  -H "Authorization: Bearer $TOKEN"
```

Parâmetros de consulta: `status` (`PENDING_REVIEW`, `APPROVED`, `REJECTED`), `limit` (1–200) e `cursor`.

### Obter uma revisão

```bash theme={null}
curl -X GET "https://api.matcher.example.com/v1/imports/contexts/{contextId}/extraction-reviews/{reviewId}" \
  -H "Authorization: Bearer $TOKEN"
```

Uma revisão carrega seu ciclo de vida, os candidatos propostos, a proveniência e o estado de vinculação:

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contextId": "550e8400-e29b-41d4-a716-446655440000",
  "sourceId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "PENDING_REVIEW",
  "candidates": [
    {
      "source": "text_layer",
      "fields": [
        { "canonicalKey": "amount", "value": "100.50", "confidence": 0.95, "page": 1 },
        { "canonicalKey": "date", "value": "2025-06-01", "confidence": 0.9, "page": 1 }
      ]
    }
  ],
  "version": 1,
  "createdAt": "2025-01-15T10:30:00Z",
  "updatedAt": "2025-01-15T10:30:00Z"
}
```

Cada candidato declara a esteira que o produziu: `text_layer` (texto do PDF, maior confiança) ou `vision` (modelo de OCR/visão, menor confiança). Os valores dos campos são **tokens literais** — o dinheiro permanece como string, nunca como um valor parseado.

## Aprovar ou rejeitar

***

### Aprovar

Aprovar uma revisão em estado `PENDING_REVIEW` executa o único repasse determinístico para o pipeline normal de ingestão (deduplicação + outbox + gatilho de matching) e vincula o job resultante à revisão. Este é o **único** caminho de um candidato de IA a uma transação conciliada, e ele só é executado mediante aprovação humana explícita.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/imports/contexts/{contextId}/extraction-reviews/{reviewId}/approve" \
  -H "Authorization: Bearer $TOKEN"
```

```json theme={null}
{
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "ingestionJobId": "550e8400-e29b-41d4-a716-446655440000",
  "candidateCount": 12
}
```

### Rejeitar

Rejeitar descarta os candidatos — nada é ingerido. O corpo é opcional; um corpo vazio é uma "rejeição sem motivo" válida.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/imports/contexts/{contextId}/extraction-reviews/{reviewId}/reject" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "poor scan quality, re-upload" }'
```

O principal que aprova ou rejeita é registrado para auditoria.

## Propostas de mapeamento

***

Antes de declarar um mapa de campos manualmente, peça ao advisor para inspecionar uma amostra representativa e propor um mapeamento **somente de configuração**. Ele é consultivo e sem efeitos colaterais: gerar uma proposta **não persiste nada**. Você confirma o resultado pelo caminho existente de declaração do mapa de campos.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/imports/contexts/{contextId}/sources/{sourceId}/mapping-proposal" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sample": "id;value;ccy;posted_at\nA1;10,50;BRL;2025-06-01\n",
    "format": "csv",
    "hints": { "locale": "pt-BR", "has_header": "true" }
  }'
```

A resposta carrega o mapa de campos proposto, o dialeto de origem e um detalhamento por campo com confiança e justificativa:

```json theme={null}
{
  "mapping": { "amount": "value", "external_id": "id" },
  "dialect": {
    "encoding": "utf-8",
    "delimiter": "semicolon",
    "decimalStyle": "comma",
    "dateStyle": "iso"
  },
  "fields": [
    { "canonicalKey": "amount", "sourceColumn": "value", "confidence": 0.92, "rationale": "numeric column with comma decimal" }
  ]
}
```

A resposta nunca carrega valores parseados, montantes ou transações.

## Buscar de um transporte externo

***

Dispare um fetch-and-ingest manual que lista todos os objetos que correspondem às coordenadas de transporte fornecidas (SFTP hoje) e transmite cada um para o pipeline de ingestão de conteúdo confiável. O corpo carrega as coordenadas de conexão mais uma **referência de credencial opaca — nunca um segredo**.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/imports/contexts/{contextId}/sources/{sourceId}/fetch" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "sftp",
    "host": "sftp.bank.example",
    "port": 22,
    "path": "outbound/returns",
    "glob": "*.ret",
    "credentialRef": "cred-handle-123",
    "format": "br/cnab240/febraban-base"
  }'
```

A resposta (`202 Accepted`) retorna um resultado por arquivo na ordem de busca. Falhas de intake por arquivo são reportadas sem fazer o lote falhar:

```json theme={null}
{
  "files": [
    { "name": "statement-2025-06.ret", "ingestionJobId": "550e8400-...", "transactionCount": 42 }
  ]
}
```

Uma falha em nível de transporte (endpoint inacessível ou credencial rejeitada) retorna `503`.

## Inspecionar erros de um job

***

Após uma importação, liste os erros de parse/normalização por linha armazenados para um job (limitados a 100 por job) para explicar importações que falharam total ou parcialmente.

```bash theme={null}
curl -X GET "https://api.matcher.example.com/v1/imports/contexts/{contextId}/jobs/{jobId}/errors" \
  -H "Authorization: Bearer $TOKEN"
```

```json theme={null}
{
  "items": [ ... ],
  "totalErrors": 137,
  "storedErrors": 100,
  "errorCap": 100,
  "truncated": true
}
```

`totalErrors` é o total de falhas sem limite; `truncated` é `true` quando ele excede o conjunto armazenado (limitado).

## Códigos de resposta

***

| Status | Significado                                                                    |
| ------ | ------------------------------------------------------------------------------ |
| `200`  | Revisão, lista, proposta de mapeamento ou erros de job retornados              |
| `202`  | Documento enfileirado / fetch aceito                                           |
| `400`  | Entrada inválida (corpo vazio, filtro de status incorreto, paginação inválida) |
| `403`  | Tenant não aderiu à extração de documentos                                     |
| `404`  | Revisão ou job não encontrado                                                  |
| `409`  | Transição de estado de revisão inválida                                        |
| `422`  | Nenhum candidato pôde ser extraído / amostra de mapeamento rejeitada a jusante |
| `503`  | Extração, revisão, proposta ou fetch não habilitados neste deployment          |
