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

# Exportaciones y disputas

> Ejecuta trabajos de exportación asíncronos para generar reportes de conciliación descargables, y abre, documenta y resuelve disputas contra excepciones.

Esta guía cubre dos flujos de trabajo de operador que terminan en un artefacto descargable o resuelto: **trabajos de exportación** (encola un reporte, consulta su estado hasta que finalice y descarga el archivo) y **disputas** (abre una disputa contra una excepción, adjunta evidencia y luego ciérrala como ganada o perdida). Ambos están delimitados por inquilino desde el JWT.

## Trabajos de exportación

***

Las exportaciones son asíncronas. Creas un trabajo delimitado a un contexto, consultas su estado por ID y descargas el archivo una vez que alcanza `SUCCEEDED`. Los estados son `QUEUED`, `RUNNING`, `SUCCEEDED`, `FAILED`, `EXPIRED` y `CANCELED`.

### Crear un trabajo de exportación

`POST` a la colección export-jobs del contexto. Responde `202 Accepted` con el ID del trabajo y una 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` — uno de `MATCHED`, `UNMATCHED`, `VARIANCE`, `EXCEPTIONS` (los alias `MATCHES` y `UNMATCHED_TRANSACTIONS` se normalizan).
* `format` — `CSV`, `JSON` o `XML` (normalizado a mayúsculas).
* `dateFrom` / `dateTo` — `YYYY-MM-DD` opcional; `dateFrom` toma por defecto 30 días antes de `dateTo`, y `dateTo` toma por defecto mañana (UTC).
* `sourceId` — filtro de fuente opcional.

<Note>`SUMMARY` y `PDF` **no** se admiten para trabajos de exportación asíncronos y se rechazan con `400`. La ventana de fechas también tiene un límite máximo de rango (una solicitud fuera de rango se rechaza en lugar de recortarse silenciosamente).</Note>

### Consultar el estado del trabajo

Lee la ruta de nivel superior del trabajo (la `statusUrl` de la creación).

```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` está presente solo cuando `status` es `FAILED`; `downloadUrl` aparece únicamente una vez que el trabajo tiene `SUCCEEDED` y el archivo aún está disponible. Puedes listar los trabajos de un contexto con `GET /v1/contexts/{contextId}/export-jobs`, listar todos los trabajos con `GET /v1/export-jobs` y cancelar un trabajo encolado o en ejecución con `POST /v1/export-jobs/{jobId}/cancel`.

### Descargar el archivo

Devuelve una URL prefirmada, el nombre de archivo original, un checksum SHA-256 y la vida útil restante de la URL en 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>Los archivos de exportación se purgan después de `expiresAt` (7 días por defecto). Una vez que un trabajo está `EXPIRED`, el archivo ya no se puede descargar — vuelve a ejecutar la exportación para regenerarlo.</Warning>

## Disputas

***

Una disputa se abre contra una **excepción** específica cuando es necesario impugnar una discrepancia de conciliación. Su ciclo de vida es `DRAFT` → `OPEN` → `PENDING_EVIDENCE` → `WON` / `LOST`.

### Abrir una disputa

`POST` a la colección disputes de la excepción.

```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` es uno de `BANK_FEE_ERROR`, `UNRECOGNIZED_CHARGE`, `DUPLICATE_TRANSACTION` u `OTHER`. El principal que abre la disputa se registra en `openedBy`.

### Enviar evidencia por URL

Adjunta una referencia a un archivo de evidencia ya alojado más un comentario descriptivo.

```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"
  }'
```

### Cargar un archivo de evidencia

Transmite los bytes brutos del archivo directamente al almacenamiento de objetos delimitado por inquilino — el comentario viaja como parámetro de consulta y el archivo como cuerpo de la solicitud. Responde `201 Created` con la disputa actualizada. Los tipos de contenido permitidos son `application/pdf`, `image/png`, `image/jpeg` y `text/csv`; el cuerpo tiene un límite 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
```

Cada elemento de evidencia almacenado se devuelve en el array `evidence` de la disputa:

```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>El endpoint de carga falla de forma segura con `503` cuando el almacenamiento de objetos no está configurado, rechaza cuerpos de tamaño excesivo con `413` y rechaza tipos de contenido fuera de la lista de permitidos con `415`. El inquilino y la disputa siempre se resuelven desde el JWT y la ruta — nunca desde el cuerpo.</Note>

### Cerrar una disputa

Registra el resultado. `won` fija el estado terminal en `WON` o `LOST`, con una nota `resolution` obligatoria.

```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"
  }'
```

Puedes listar disputas con `GET /v1/disputes` (filtra por `state`, `category`, rango de fechas; ordena y pagina con cursor) y obtener una con `GET /v1/disputes/{disputeId}`.

## Códigos de respuesta

***

| Estado | Significado                                                                                            |
| ------ | ------------------------------------------------------------------------------------------------------ |
| `200`  | Datos de exportación/disputa devueltos                                                                 |
| `201`  | Archivo de evidencia cargado                                                                           |
| `202`  | Trabajo de exportación aceptado                                                                        |
| `400`  | Entrada inválida (tipo/formato de reporte no admitido, rango de fechas incorrecto, categoría inválida) |
| `404`  | Contexto, trabajo de exportación, excepción o disputa no encontrados                                   |
| `409`  | Transición de estado de disputa inválida                                                               |
| `413`  | El archivo de evidencia excede el límite de 10 MiB                                                     |
| `415`  | Tipo de contenido de evidencia no está en la lista de permitidos                                       |
| `422`  | Campo mal formado                                                                                      |
| `503`  | Almacenamiento de exportación o evidencia no configurado                                               |
