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

# Test mode (Sandbox)

> Integra Rail de punta a punta sin tocar un banco real — credenciales mágicas + data determinista.

Test mode te permite construir y validar tu integración **sin conectar cuentas bancarias reales**. Las keys `rail_sk_test_…` / `rail_pk_test_…` operan contra un **banco fake** que devuelve cuentas y movimientos deterministas, con los mismos shapes, eventos y errores que producción.

<Note>
  El modo se infiere del **prefijo de la key** — no hay parámetro aparte. Una `rail_sk_test_…` opera en sandbox; una `rail_sk_live_…` en producción. Los recursos de un modo **nunca** se ven desde el otro: un `sk_test` no puede leer un link `live` (y viceversa).
</Note>

## 1. Obtén tus test keys

En [dashboard.rail.cl](https://dashboard.rail.cl) → **Para desarrolladores → API keys**, crea una key con **Modo: Test**. El switch **Test/Live** de la barra superior cambia toda la vista del dashboard (conexiones, eventos, webhooks) al modo elegido.

```bash theme={null}
# Todos los ejemplos usan tu secret key de test:
export RAIL_SK=rail_sk_test_…
```

## 2. Credenciales mágicas

En test mode **no puedes conectar cuentas reales**. Usa el **password mágico** `rail-sandbox` + un **RUT mágico** que selecciona el escenario:

| RUT            | Password       | Escenario                                                                                                            |
| -------------- | -------------- | -------------------------------------------------------------------------------------------------------------------- |
| `11.111.111-1` | `rail-sandbox` | <Icon icon="circle-check" color="#16a34a" /> Persona — 1 cuenta vista + 1 tarjeta de crédito, \~50 movimientos       |
| `22.222.222-2` | `rail-sandbox` | <Icon icon="circle-check" color="#16a34a" /> Empresa — cuenta corriente CLP + USD (requiere `holder_type: business`) |
| `33.333.333-3` | `rail-sandbox` | <Icon icon="lock" color="#f59e0b" /> MFA challenge — el sync pide un código (mágico: `123456`)                       |
| `44.444.444-4` | `rail-sandbox` | <Icon icon="circle-xmark" color="#dc2626" /> Credenciales inválidas — `rejected_credentials`                         |
| `55.555.555-5` | `rail-sandbox` | <Icon icon="inbox" color="#9ca3af" /> Sin productos — 0 cuentas (cuenta vacía)                                       |

<Note>
  Cualquier otro RUT, o un password distinto de `rail-sandbox`, devuelve `credentials_invalid` — **nunca** se dispara un scraping real. La data es **determinista por link**: el mismo link devuelve siempre los mismos montos y glosas.
</Note>

## 3. Conecta un banco fake (sin widget)

En test mode puedes crear un link directo con `POST /v1/links` — el `bank_id` es cosmético (la data es fake igual). El sync arranca en background.

```bash theme={null}
curl https://api.rail.cl/v1/links \
  -X POST \
  -H "Authorization: Bearer $RAIL_SK" \
  -H "Content-Type: application/json" \
  -d '{
    "bank_id": "santander",
    "credentials": { "rut": "11.111.111-1", "password": "rail-sandbox" }
  }'
```

Response (el link arranca `pending` y sincroniza en background):

```json theme={null}
{
  "object": "link",
  "id": "link_8a2f4c6e1b9d5037",
  "mode": "test",
  "institution": { "id": "cl_santander", "country": "cl" },
  "status": "pending"
}
```

## 4. Espera el sync y lee la data

El link emite `refresh_intent.succeeded` al terminar (unos segundos). Puedes consultar el `refresh_intent` o directamente leer las cuentas:

```bash theme={null}
curl "https://api.rail.cl/v1/accounts?link_id=link_8a2f4c6e1b9d5037" \
  -H "Authorization: Bearer $RAIL_SK"
```

```json theme={null}
[
  {
    "object": "account",
    "id": "acc_7d2f3a8c1e9b4502",
    "name": "Cuenta Vista",
    "type": "checking",
    "currency": "CLP",
    "balance": { "available": 842000, "current": 842000 },
    "mode": "test"
  },
  {
    "object": "account",
    "id": "acc_1b9d5037a2f4c6e8",
    "name": "Tarjeta de Crédito Visa",
    "type": "credit_card",
    "currency": "CLP",
    "balance": { "available": 2100000, "limit": 3500000 },
    "mode": "test"
  }
]
```

Los movimientos salen igual que en producción (montos bigint con signo, glosas chilenas realistas):

```bash theme={null}
curl "https://api.rail.cl/v1/accounts/acc_7d2f3a8c1e9b4502/movements?per_page=5" \
  -H "Authorization: Bearer $RAIL_SK"
```

## 5. Prueba el flujo MFA

El RUT `33.333.333-3` fuerza un **MFA challenge**: el `refresh_intent` pasa a `requires_mfa`. Responde con el código mágico `123456` para destrabarlo (cualquier otro código lo rechaza). Es el mismo flujo que un banco real con OTP — ideal para validar tu manejo de MFA async. Ver [MFA handling](/guides/mfa-handling).

## 6. Prueba tus webhooks

Los webhook endpoints registrados en **modo test** reciben los eventos de tus links de sandbox (`refresh_intent.succeeded`, `link.credentials_invalid`, etc.) — aislados de tus endpoints `live`.

Para validar tu receiver (firma HMAC + retry) **sin correr un sync**, dispara un evento de prueba a demanda:

```bash theme={null}
curl https://api.rail.cl/v1/sandbox/events/fire \
  -X POST \
  -H "Authorization: Bearer $RAIL_SK" \
  -H "Content-Type: application/json" \
  -d '{ "type": "refresh_intent.succeeded" }'
```

El evento llega a tus endpoints de modo test con IDs centinela (`acc_00000000`) — es data de prueba, no consultable. Tipos disparables: `refresh_intent.succeeded`, `refresh_intent.failed`, `refresh_intent.requires_mfa`, `link.credentials_invalid`, `link.expired`. Ver [Webhooks](/guides/webhooks).

## Widget en test mode

El widget de Rail Connect, inicializado con tu `rail_pk_test_…`, corre en **modo sandbox**: muestra un indicador **"Modo prueba"** y precarga las credenciales mágicas en el formulario para que las pruebes sin salir del flujo.

```html theme={null}
<script src="https://widget.rail.cl/v1/embed.js"></script>
<script>
  Rail.openWidget({
    token: 'wt_…',                 // emitido con tu sk_test o pk_test
    publishableKey: 'rail_pk_test_…',
    onSuccess: (et) => { /* canjéalo en tu backend */ },
  });
</script>
```

## Pasar a producción

Cuando tu integración funcione en test, cambia las keys `_test_` por `_live_` — **no cambia nada más de tu código** (las URLs, shapes y flujos son idénticos). El único cambio es que cada sync ahora consulta el banco real.

<CardGroup cols={2}>
  <Card title="Autenticación" icon="key" href="/authentication">
    Los 4 tipos de credenciales y el modelo test/live.
  </Card>

  <Card title="Webhooks" icon="bell" href="/guides/webhooks">
    Recibe los eventos de tus links de sandbox.
  </Card>
</CardGroup>
