Conciliación bancaria

MODO PRUEBA

La conciliación de 3 vías de Winal (ledger propio ↔ liquidación del conector ↔ estado de cuenta bancario) suma una 4ª vía: importa el CSV del estado de cuenta que descargas del portal de tu banco y Winal lo casa contra los abonos que esperabas recibir por tus liquidaciones — sin capturar nada a mano.

Importa un estado de cuenta

El archivo viaja como multipart/form-data (o como cuerpo crudo, con filename por query). No exige Idempotency-Key: no mueve dinero, solo importa y casa datos ya asentados — su idempotencia real es el hash del archivo. Metadatos requeridos: bank, period_start/period_end (yyyy-MM-dd); tolerance_days es opcional (default: la tolerancia estándar de la conciliación de liquidaciones).

bash
curl -s https://api.winal.com.mx/v1/reconciliation/bank-statements \
  -H "Authorization: Bearer $SK" \
  -F "bank=bbva" \
  -F "period_start=2026-07-01" \
  -F "period_end=2026-07-08" \
  -F "preset=bbva" \
  -F "file=@estado_bbva.csv;type=text/csv"
201 · respuesta real
{
  "id": "271a21c8-be04-4d6e-909a-8f1394fd333a",
  "object": "bank_statement",
  "bank": "bbva",
  "period_start": "2026-07-01",
  "period_end": "2026-07-08",
  "filename": "estado_bbva.csv",
  "lines_total": 2,
  "matched": 0,
  "partial": 0,
  "unmatched": 1,
  "exceptions": 2,
  "already_imported": false
}

Mapeo de columnas: preset o explícito

Cada banco exporta el estado de cuenta con su propio layout de columnas — por eso el mapeo siempre es explícito. preset pre-llena tres conocidos, pero ninguno está verificado contra un export real todavía (el propio código lo advierte): confírmalo contra tu archivo antes de confiar en él en producción, o usa el mapeo explícito directamente.

Presetfechadescripciónreferenciacargoabonoencabezado
bbvacol. 0col. 1col. 2col. 3col. 4
banortecol. 0col. 1col. 2col. 3
santandercol. 0col. 1col. 2col. 3col. 4

Mapeo explícito (0-based), si tu export no coincide con ningún preset o quieres verificarlo tú mismo: date_column, description_column, credit_column (abono), debit_column (cargo) son requeridos; reference_column es opcional; has_header (default true, manda "false" si tu CSV no trae encabezado).

Lo que el parser SÍ tolera por ti
Encoding (UTF-8 con/sin BOM, o latin1 — el legado de banca mexicana), comillas CSV con comas dentro de la descripción, y montos con símbolo de moneda/separador de miles ("$1,234.56"). Solo CSV en fase 0 — si tu banco solo exporta .xlsx, conviértelo primero (Excel/LibreOffice "Guardar como").

Consulta el estado de cuenta importado

bash
curl -s https://api.winal.com.mx/v1/reconciliation/bank-statements -H "Authorization: Bearer $SK"
200 · respuesta real
{
  "object": "list",
  "data": [
    {
      "id": "271a21c8-be04-4d6e-909a-8f1394fd333a",
      "object": "bank_statement",
      "bank": "bbva",
      "period_start": "2026-07-01",
      "period_end": "2026-07-08",
      "filename": "estado_bbva.csv",
      "lines_total": 2,
      "imported_at": "2026-07-08T02:22:42.583562+00:00"
    }
  ]
}

Líneas del estado de cuenta, filtrables por estado de casado

bash
curl -s "https://api.winal.com.mx/v1/reconciliation/bank-statements/271a21c8-.../lines?match_status=unmatched" \
  -H "Authorization: Bearer $SK"
200 · respuesta real
{
  "object": "list",
  "data": [
    {
      "id": 3,
      "object": "bank_statement_line",
      "value_date": "2026-07-01",
      "description": "SPEI RECIBIDO ANTECH",
      "reference": "REF001",
      "credit_minor": 50000,
      "currency": "MXN",
      "match_status": "unmatched"
    },
    {
      "id": 4,
      "object": "bank_statement_line",
      "value_date": "2026-07-02",
      "description": "COMISION MENSUAL",
      "reference": "REF002",
      "debit_minor": 15000,
      "currency": "MXN",
      "match_status": "unmatched"
    }
  ]
}

match_status es matched, partial o unmatched; el filtro ?match_status= es opcional (sin filtro, trae todas las líneas). Cada línea trae o credit_minor o debit_minor, nunca ambos — un movimiento bancario es uno solo.

Los 3 tipos de excepción de la conciliación bancaria

Se suman a los tipos ya existentes de la conciliación de liquidaciones (missing_local, missing_in_report, amount_mismatch, fee_mismatch, unparsed_line) — visibles todas juntas en el visor de excepciones del portal.

TipoQué significa
bank_deposit_unexpectedHay un abono en el estado de cuenta que no corresponde a ninguna liquidación esperada — dinero que entró sin que Winal supiera de dónde viene.
bank_deposit_missingWinal esperaba un abono por una liquidación ya reportada por el conector, pero no aparece en el estado de cuenta bancario dentro de la tolerancia de días configurada.
bank_amount_mismatchHay un abono cerca de la fecha esperada, pero el monto no cuadra con la liquidación reportada.
json · excepción real, tras el import de arriba
{
  "object": "recon_exception",
  "id": 4,
  "connector_key": "bank",
  "provider_ref": "REF001",
  "type": "bank_deposit_unexpected",
  "report_amount_minor": 50000,
  "detail": "Abono del estado de cuenta sin ninguna liquidación esperada que lo explique.",
  "created_at": "2026-07-08T02:22:42.623309+00:00"
}

Las excepciones de conciliación bancaria comparten el mismo visor del portal que las de liquidación de conectores — se distinguen por connector_key: "bank" y por su type. No hay un endpoint público de /v1/* para listarlas: revísalas en portal → Conciliación → Excepciones.

Endpoints

MétodoRutaNotas
POST/v1/reconciliation/bank-statementsMultipart o cuerpo crudo; tope de archivo 5 MiB.
GET/v1/reconciliation/bank-statementsLista los estados de cuenta importados.
GET/v1/reconciliation/bank-statements/{id}/lines?match_status=Filtro opcional por estado de casado.

Errores de bank_statement

HTTPcodeCausa
400bank_statement.bank_requiredFalta bank.
400bank_statement.invalid_periodFaltan o son inválidos period_start/period_end, o period_start > period_end.
400bank_statement.invalid_tolerancetolerance_days negativo.
400bank_statement.unknown_presetpreset no es bbva/banorte/santander.
400bank_statement.mapping_requiredNo se dio preset ni un mapeo explícito completo.
400bank_statement.invalid_mappingEl mapeo explícito de columnas es inconsistente.
400bank_statement.invalid_match_status?match_status= no es matched/unmatched/partial.
400bank_statement.too_largeEl archivo excede 5 MiB.
400bank_statement.parse_errorUna fila no parsea: fecha/monto inválidos, o trae abono Y cargo (o ninguno) a la vez.

Ver el envelope completo de error en Errores.