Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.rail.cl/llms.txt

Use this file to discover all available pages before exploring further.

Por qué existen

Rail corre syncs automáticos cada 4h por cada link. Pero a veces el cliente quiere forzar un sync ya — por ejemplo cuando el user abre la app y quiere ver lo más reciente. Un refresh intent representa ese deseo de sync on-demand. Su ID es ri_ + 16 chars hex.
{
  "object": "refresh_intent",
  "id": "ri_a1b2c3d4e5f6a7b8",
  "link_id": "link_8a2f4c6e1b9d5037",
  "status": "succeeded",
  "refresh_type": "full",
  "requires_mfa": null,
  "created_at": "2026-06-03T15:00:00Z",
  "started_at": "2026-06-03T15:00:01Z",
  "completed_at": "2026-06-03T15:00:45Z",
  "error_code": null
}

Crear

curl https://api.rail.cl/v1/refresh_intents \
  -X POST \
  -H "Authorization: Bearer rail_sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "link_id": "link_xxx",
    "refresh_type": "full"
  }'
refresh_type:
  • full — todas las cuentas, todos los movs (default).
  • historical — incluye movs viejos (60+ días).
  • only_last — solo cuentas (skip movs). Más rápido.

Lifecycle

statusSignifica
createdEncolado. Aún no empezó.
in_progressEl worker está syncando.
requires_mfaEl banco pidió MFA. Ver abajo.
succeededSync terminado OK.
failedSync falló. Ver error_code.

MFA async

Algunos bancos (Santander, BCI a veces) piden MFA en cada sync. Cuando eso pasa:
  1. El intent queda en status: requires_mfa.
  2. El campo requires_mfa.widget_token contiene un ri_{intentId}_sec_… listo para abrir el widget.
  3. Tu frontend abre el widget con ese token.
  4. User resuelve el MFA dentro del widget.
  5. El widget cierra, el sync continúa server-side.
  6. El intent pasa a succeeded o failed.
{
  "object": "refresh_intent",
  "id": "ri_xxx",
  "status": "requires_mfa",
  "requires_mfa": {
    "widget_token": "ri_xxx_sec_abc123…",
    "expires_at": "2026-06-03T15:10:00Z"
  }
}

Polling vs Webhooks

Dos formas de saber cuándo termina:

Polling

curl https://api.rail.cl/v1/refresh_intents/ri_xxx \
  -H "Authorization: Bearer rail_sk_live_…"
Cada 5-10 segundos hasta que status sea succeeded, failed o requires_mfa.

Webhooks (recomendado)

Suscribite a los eventos refresh_intent.succeeded, refresh_intent.failed, refresh_intent.requires_mfa. Ver Guías → Webhooks.

Cooldown y deduplicación

  • Cooldown 5min: si pediste un intent para un link, no podés pedir otro full hasta 5min después. Para only_last no hay cooldown.
  • Unique in-progress: solo puede haber 1 intent activo por link a la vez. Si pedís otro, te devolvemos el existente.
# Si ya hay uno in_progress, devuelve ese (no crea otro)
curl https://api.rail.cl/v1/refresh_intents \
  -X POST \
  -d '{"link_id": "link_xxx", "refresh_type": "full"}'
# → 200 con el intent activo, no 201

Error codes comunes

error_codeSignifica
bank_unavailableEl banco está caído o muy lento. Reintentar en 10min.
rejected_credentialsClave o RUT inválido. El user debe re-conectar.
requires_mfa_user_timeoutSe emitió wt_* pero el user no resolvió en 10min.
bank_format_changeEl banco cambió su HTML y nuestro parser rompió. Rail está sobre eso.