# BancoEstado Empresas

> Saldos y movimientos de cuenta corriente del portal de BancoEstado Empresas, servidos al instante desde la caché de Connect.



`banco_estado` sincroniza dos alcances del portal de BancoEstado Empresas hacia el plano persistido de Connect: los saldos de cuenta corriente y los movimientos de la cartola. El login usa los mismos tres datos con que se entra a la banca en línea; dos tools de consulta leen esa caché al instante. Cada llamada identifica a la empresa por el `conn_…` de su conexión (en REST, el header `X-Connect-Connection`).

## Una sola sesión activa por usuario [#una-sola-sesión-activa-por-usuario]

Es la particularidad que gobierna todo lo demás, y conviene saberla antes de conectar:

> BancoEstado admite **una sola sesión activa por usuario**. Mientras corre una sincronización no vas a poder entrar al portal, y si estás dentro del portal la sincronización va a fallar. Conviene dejarla agendada fuera del horario en que usas la banca en línea.

Cerrar el navegador no libera la sesión: el portal la mantiene abierta unos minutos más. Por eso Connect cierra sesión siempre al terminar, y por eso una sincronización que se cruza con una persona dentro del portal devuelve `409 connection_session_pending` en vez de un error genérico.

## Qué necesitas para conectar [#qué-necesitas-para-conectar]

La **clave de banca en línea de empresas** entra por el [enlace de conexión](/docs/empezar/conectar), en tres campos:

| Campo                   | Qué es                                               |
| ----------------------- | ---------------------------------------------------- |
| RUT empresa/institución | La empresa que esta conexión va a leer.              |
| RUT usuario             | El RUT de la persona que inicia sesión en el portal. |
| Clave                   | Su clave de banca en línea de BancoEstado Empresas.  |

Que los dos RUT vayan separados tiene una razón: quien entra al portal casi nunca es la empresa, y un mismo usuario puede acceder a varias. Connect usa ese acceso solo para leer, revocarlo desde el dashboard es inmediato, y la clave entra por el enlace de un solo uso, directo de quien la tiene, sin cruzar tu código.

El segundo factor de BancoEstado (BE Pass, BE Face) autoriza **operaciones**, como transferencias y nóminas, no la consulta: una conexión de solo lectura no lo dispara.

## Los alcances [#los-alcances]

| Alcance       | Qué trae                                                                                     | Tool que lo lee                      |
| ------------- | -------------------------------------------------------------------------------------------- | ------------------------------------ |
| `saldos`      | El saldo contable y el disponible de cada cuenta, más sus retenciones, como una foto por día | `banco_estado.saldos.consultar`      |
| `movimientos` | Los movimientos de la cartola del período, con documento, glosa, oficina y saldo arrastrado  | `banco_estado.movimientos.consultar` |

Cada conexión habilita sus alcances desde el dashboard; consultar uno apagado responde `403 alcance_not_enabled`.

## Sincronizar [#sincronizar]

Los dos alcances en la misma llamada comparten un único login contra el banco. Aquí eso no es una optimización: como el banco admite una sola sesión por usuario, un segundo login dentro del mismo trabajo sería un rechazo.

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/banco_estado.conexion.sincronizar/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Content-Type: application/json" \
  -d '{"input":{"periodo":"2026-08","alcances":["saldos","movimientos"]}}'
```

La llamada encola el trabajo y responde de inmediato, sin datos:

```json
{
  "data": {
    "periodo": "2026-08",
    "estado": "encolado",
    "jobId": "sjb_...",
    "yaEnCurso": false
  },
  "meta": { "request_id": "req_...", "tool_id": "banco_estado.conexion.sincronizar", "plane": "read" }
}
```

Un trabajo encolado todavía no acredita una sincronización. El resultado por alcance (`status`, `recordsSynced`, `detalle` y `marcador`) se lee en el job con `GET /v1/syncs/{id}` de la [API de control](/docs/api-control), o llega por [webhook](/docs/operar/webhooks) con los eventos `sync.*`. Un `movimientos` en `partial` guardó las filas legibles y dice en `marcador` qué parte de la cartola quedó sin cubrir.

Con un período ya cerrado, `saldos` devuelve cero con un `detalle` que lo explica: la foto del saldo existe solo para el período corriente, y ese cero no significa que la cuenta esté vacía. `movimientos` cubre cualquier período sincronizado.

## Verdades operativas [#verdades-operativas]

### Los saldos son una foto por día [#los-saldos-son-una-foto-por-día]

Cada fila de `saldos.consultar` es el saldo de una cuenta en un día (`observedDay`), con la hora en que el banco la reportó. Sincronizar dos veces el mismo día actualiza esa foto en vez de agregar otra. Las retenciones vienen desglosadas (a un día, a dos días, y el resto agrupado), más el total.

### Los montos son números, con la convención del libro del banco [#los-montos-son-números-con-la-convención-del-libro-del-banco]

`monto` es la magnitud **sin signo**; `type` dice si la plata sale (`credit`) o entra (`debit`) según el libro del banco, que invierte lo que una cartola muestra; y `display` trae el monto ya formateado a la chilena, con su signo. Es el mismo contrato de los otros tres bancos de Connect, así que un consumidor que ya lee uno lee este sin cambios.

`saldo` es distinto: es el saldo arrastrado tras el movimiento, o sea un balance. No lleva `type` y conserva su propio signo, porque un sobregiro es negativo.

### Dos cartolas del banco, una sola caché [#dos-cartolas-del-banco-una-sola-caché]

El banco muestra los movimientos en dos cartolas: la **cartola en línea**, que sigue abierta, y las **históricas**, que ya cerró. No van por mes: el banco cierra una cartola cuando junta cierta cantidad de movimientos, así que un mismo día puede quedar repartido entre la que cerró y la siguiente. El conector lee las dos y las guarda en la misma tabla con la misma identidad por movimiento, así que un movimiento que aparezca en ambas no se duplica. El campo `origen` de cada fila dice por cuál se trajo.

### El período de cada fila es el mes de su fecha [#el-período-de-cada-fila-es-el-mes-de-su-fecha]

Cada movimiento queda guardado bajo el mes de su propia fecha (`periodo`), no bajo el período con que se pidió la sincronización: el banco no se limita al mes pedido, y una sincronización puede traer días del mes anterior o del siguiente. Por eso `periodo` en `banco_estado.movimientos.consultar` filtra por la fecha del movimiento, y sincronizar pidiendo otro período nunca duplica filas.

### Movimientos provisorios y cierre nocturno [#movimientos-provisorios-y-cierre-nocturno]

Durante el día, la cartola en línea muestra algunos movimientos **provisorios**: el banco todavía no los contabiliza. En el cierre nocturno, entre la medianoche y cerca de las 04:00 (hora de Chile), el banco los saca y los vuelve a publicar en su versión definitiva, a veces con otra glosa o con otro número de documento.

Connect deja los movimientos guardados iguales a la cartola del banco. En cada sincronización, dentro de los días que leyó completos:

* un movimiento que el banco ya no muestra deja de aparecer en `banco_estado.movimientos.consultar`;
* uno que el banco vuelve a mostrar, reaparece.

Así un provisorio y su versión definitiva no quedan los dos. Lo mismo pasa cuando el banco recalcula el saldo de un movimiento: queda la versión nueva. La contracara es que un movimiento del día puede no aparecer durante unas horas de la noche, igual que en el portal del banco. Nada se borra: lo que el banco vuelve a mostrar, vuelve a aparecer.

Cada movimiento trae además `estado`: `provisorio` mientras el banco no lo contabiliza y `definitivo` cuando ya lo hizo. En los dos casos el movimiento ocurrió: lo que cambia es si el banco todavía puede reemplazar su versión. En chequera lo marca el propio banco. En cuenta corriente, que no trae marca, un movimiento queda `provisorio` mientras su fecha sea hoy o posterior, así que un definitivo con fecha adelantada se ve `provisorio` hasta que llega su fecha. La cartola histórica siempre es `definitivo`. El estado se actualiza en cada sincronización, y el filtro `estado` de `banco_estado.movimientos.consultar` trae solo los de uno de los dos.

Un día cuenta como completo solo si la sincronización leyó entera la cartola que lo contiene; los días de una cartola que quedó a medias no se tocan. El primer día de la cartola en línea cuenta solo si también se leyó completa la histórica con que lo comparte.

**Si guardas los movimientos en tu sistema**, no te limites a agregar las filas nuevas: la respuesta no trae un identificador por movimiento, y un movimiento puede cambiar de glosa, documento o saldo, o dejar de aparecer. En cada pasada, vuelve a leer al menos el mes en curso y el anterior (con `periodo`) y reemplaza esos meses completos en tu copia, de preferencia después de las 04:00. Si una cuenta tiene poco movimiento, su cartola abierta puede empezar varios meses atrás: en ese caso relee desde el mes del movimiento más antiguo con `origen: "linea"`. Si solo te interesa lo definitivo, filtra con `estado: "definitivo"`; un definitivo también puede cambiar de saldo cuando el banco lo recalcula, así que el reemplazo por meses sigue haciendo falta.

## Errores que vas a ver [#errores-que-vas-a-ver]

| Código                               | Qué significa                                                                                       | Qué hacer                                                                                                                                             |
| ------------------------------------ | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `409 connection_session_pending`     | El banco no tiene una sesión viva para esta conexión, o ya hay una sesión abierta para ese usuario. | Si hay alguien dentro del portal, que cierre sesión (o espera unos minutos a que expire) y reintenta. Es la contracara de la sesión única.            |
| `428 connection_credential_required` | La conexión no tiene una credencial viva: nunca se vinculó, venció o fue revocada.                  | Emite un enlace de reconexión y pide la clave de nuevo. No reintentes con la credencial anterior: BancoEstado bloquea la cuenta tras varios rechazos. |
| `409 connection_busy`                | La conexión está en uso o el servicio alcanzó temporalmente su capacidad.                           | Espera unos segundos y reintenta. No reconectes ni vuelvas a ingresar credenciales.                                                                   |
| `409 connection_sync_in_progress`    | Ya corre una sincronización de esa conexión para ese período.                                       | Espera a que termine, o consulta directamente: puede que ya haya datos.                                                                               |
| `403 alcance_not_enabled`            | La conexión no tiene habilitado el alcance que la tool pide.                                        | Habilítalo en la conexión desde el dashboard, o quítalo del input de la sincronización.                                                               |

Cada código, con su envelope completo, está en el [catálogo de errores](/docs/operar/errores).

## Próximos pasos [#próximos-pasos]

* Las cuatro tools con su contrato: [referencia de `banco_estado`](/docs/referencia/banco_estado).
* El modelo de dos pasos detrás de cada `.consultar`: [Sincronizar y consultar](/docs/conceptos/sincronizar-consultar).
* Que cada sync avise al terminar: [Webhooks](/docs/operar/webhooks).
