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

# Exportações e disputas

> Rode jobs de exportação assíncronos para gerar relatórios de conciliação para download, e abra, comprove com evidências e resolva disputas contra exceções.

Este guia cobre dois workflows de operador que terminam em um artefato baixável ou resolvido. Com **jobs de exportação** você põe um relatório na fila, consulta até ele ter sucesso e baixa o arquivo. Com **disputas** você abre uma disputa contra uma exceção, anexa evidências e depois a encerra como ganha ou perdida. Os dois têm escopo de tenant vindo do JWT.

## Jobs de exportação

***

As exportações são assíncronas. Você cria um job com escopo em um contexto, consulta o status dele pelo ID e baixa o arquivo quando ele chega em `SUCCEEDED`. Os status são `QUEUED`, `RUNNING`, `SUCCEEDED`, `FAILED`, `EXPIRED` e `CANCELED`.

### Criar um job de exportação

Faça `POST` na coleção de jobs de exportação do contexto. Responde `202 Accepted` com o ID do job e uma URL de consulta.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/export-jobs" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reportType": "MATCHED",
    "format": "CSV",
    "dateFrom": "2025-01-01",
    "dateTo": "2025-01-31",
    "sourceId": "550e8400-e29b-41d4-a716-446655440000"
  }'
```

```json theme={null}
{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "QUEUED",
  "statusUrl": "/v1/export-jobs/550e8400-e29b-41d4-a716-446655440001"
}
```

* `reportType`: um entre `MATCHED`, `UNMATCHED`, `VARIANCE`, `EXCEPTIONS` (os aliases `MATCHES` e `UNMATCHED_TRANSACTIONS` normalizam para esses valores).
* `format`: `CSV`, `JSON` ou `XML` (normalizado para maiúsculas).
* `dateFrom` / `dateTo`: `YYYY-MM-DD` opcional. `dateFrom` tem como padrão 30 dias antes de `dateTo`, e `dateTo` tem como padrão amanhã (UTC).
* `sourceId`: filtro de fonte opcional.

<Note>Os jobs de exportação assíncronos **não** aceitam `SUMMARY` nem `PDF`. Uma requisição com qualquer um dos dois retorna `400`. A janela de datas também tem um intervalo máximo. Uma requisição fora do intervalo retorna um erro em vez de uma janela cortada em silêncio.</Note>

### Consultar o status do job

Leia a rota de job de nível raiz (a `statusUrl` da criação).

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

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reportType": "MATCHED",
  "format": "CSV",
  "status": "SUCCEEDED",
  "recordsWritten": 4250,
  "bytesWritten": 524288,
  "fileName": "matched_report_2025-01-31.csv",
  "createdAt": "2025-01-15T10:30:00Z",
  "startedAt": "2025-01-15T10:30:05Z",
  "finishedAt": "2025-01-15T10:35:00Z",
  "expiresAt": "2025-01-16T10:30:00Z",
  "downloadUrl": "https://storage.example.com/exports/matched_report.csv?token=abc"
}
```

`error` aparece apenas quando `status` é `FAILED`. `downloadUrl` aparece apenas quando o job chegou a `SUCCEEDED` e o arquivo ainda está disponível. Você pode listar os jobs de um contexto com `GET /v1/contexts/{contextId}/export-jobs`, listar todos os jobs com `GET /v1/export-jobs` e cancelar um job na fila ou em execução com `POST /v1/export-jobs/{jobId}/cancel`.

### Baixar o arquivo

Retorna uma URL pré-assinada, o nome original do arquivo, um checksum SHA-256 e o tempo de vida restante da URL em segundos.

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

```json theme={null}
{
  "downloadUrl": "https://storage.example.com/exports/report.csv?token=abc",
  "fileName": "matched_report.csv",
  "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "expiresIn": 3600
}
```

<Warning>Os arquivos de exportação são apagados depois de `expiresAt` (padrão de 7 dias). Quando um job fica `EXPIRED`, o arquivo não pode mais ser baixado. Rode a exportação de novo para gerá-lo outra vez.</Warning>

## Disputas

***

Você abre uma disputa contra uma **exceção** específica quando precisa contestar uma divergência de conciliação. O ciclo de vida dela começa em `DRAFT` → `OPEN`. A partir de `OPEN`, uma disputa pode ir para `PENDING_EVIDENCE` (e voltar para `OPEN`) ou encerrar direto como `WON` / `LOST`. Apenas `WON` é terminal. Você pode reabrir uma disputa `LOST` para `OPEN`.

### Abrir uma disputa

Faça `POST` na coleção de disputas da exceção.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/exceptions/{exceptionId}/disputes" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "BANK_FEE_ERROR",
    "description": "Transaction amount differs from invoice"
  }'
```

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "exceptionId": "550e8400-e29b-41d4-a716-446655440001",
  "category": "BANK_FEE_ERROR",
  "state": "OPEN",
  "description": "Transaction amount differs from invoice",
  "openedBy": "user@example.com",
  "evidence": [],
  "createdAt": "2025-01-15T10:30:00Z",
  "updatedAt": "2025-01-15T10:30:00Z"
}
```

`category` é um entre `BANK_FEE_ERROR`, `UNRECOGNIZED_CHARGE`, `DUPLICATE_TRANSACTION` ou `OTHER`. O campo `openedBy` registra o principal que abriu.

### Enviar evidência por URL

Anexe uma referência a um arquivo de evidência já hospedado mais um comentário que o descreve.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/disputes/{disputeId}/evidence" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "Attached bank statement showing correct amount",
    "fileUrl": "https://storage.example.com/evidence/doc123.pdf"
  }'
```

### Fazer upload de um arquivo de evidência

Envie os bytes brutos do arquivo direto para o object storage com escopo de tenant. O comentário viaja como parâmetro de query e o arquivo como corpo da requisição. Responde `201 Created` com a disputa atualizada. Os content types permitidos são `application/pdf`, `image/png`, `image/jpeg` e `text/csv`. O corpo tem limite de 10 MiB.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/disputes/{disputeId}/evidence/upload?comment=Bank%20statement%20showing%20correct%20amount" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @statement.pdf
```

O array `evidence` da disputa lista cada item de evidência guardado:

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "disputeId": "550e8400-e29b-41d4-a716-446655440001",
  "comment": "Bank statement showing correct amount",
  "submittedBy": "user@example.com",
  "fileUrl": "https://storage.example.com/evidence/doc123.pdf",
  "submittedAt": "2025-01-15T10:30:00Z"
}
```

<Note>
  O endpoint de upload falha fechado com `503` quando você não configura o object storage. Ele rejeita corpos grandes demais com `413` e content types fora da allowlist com `415`. O tenant sempre vem do JWT e a disputa vem do caminho, nunca do corpo.
</Note>

### Encerrar uma disputa

Registre o resultado. `won` define o estado como `WON` (terminal) ou `LOST` (reabrível), com uma nota `resolution` obrigatória.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/disputes/{disputeId}/close" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "won": true,
    "resolution": "Counterparty acknowledged the error and issued correction"
  }'
```

Você pode listar disputas com `GET /v1/disputes` e buscar uma com `GET /v1/disputes/{disputeId}`. O endpoint de lista filtra por `state`, `category` e intervalo de datas, e oferece suporte a ordenação e paginação por cursor.

## Códigos de resposta

***

| Status | Significado                                                                                               |
| ------ | --------------------------------------------------------------------------------------------------------- |
| `200`  | Dados de exportação ou de disputa retornados                                                              |
| `201`  | Arquivo de evidência enviado                                                                              |
| `202`  | Job de exportação aceito                                                                                  |
| `400`  | Entrada inválida (tipo ou formato de relatório não aceito, intervalo de datas errado, categoria inválida) |
| `404`  | Contexto, job de exportação, exceção ou disputa não encontrado                                            |
| `409`  | Transição de estado de disputa inválida                                                                   |
| `413`  | O arquivo de evidência ultrapassa o limite de 10 MiB                                                      |
| `415`  | Content type da evidência fora da allowlist                                                               |
| `422`  | Campo malformado                                                                                          |
| `503`  | Armazenamento de exportação ou de evidência não configurado                                               |
