# Llamar a la API

> El cliente REST, el token vigente y los Intents.


`andco.rest` habla con la API de Andco poniendo el token vigente en cada petición. No manipulas cabeceras ni renuevas tokens a mano.

## Los cuatro métodos

```ts
const { data, error } = await andco.rest.http.GET("/accounts");

await andco.rest.http.POST("/transfers", { body: { amount: 1000 } });
await andco.rest.http.PATCH("/profile", { body: { name: "Alicia" } });
await andco.rest.http.DELETE("/sessions/actual");
```

Las rutas y los tipos vienen del contrato OpenAPI de Andco: `data` ya sale tipado, no lo pones tú.

`andco.rest.http` es [`openapi-fetch`](https://openapi-ts.dev/openapi-fetch/) por debajo, generado desde ese contrato. `AndcoRest` solo le agrega el tipo de error propio y `.throwOnError()`; el cliente sin envolver está en `andco.rest.raw`.

## Resultados, no excepciones

Todo devuelve `{ data, error }` y exactamente uno de los dos es nulo.

```ts
const { data, error } = await andco.rest.http.GET("/accounts");
if (error) {
  console.error(error.code, error.message);
  return;
}
use(data);
```

Esto obliga a mirar el error en el punto donde puede ocurrir, en vez de dejarlo subir hasta un `catch` lejano que no sabe qué hacer con él.

## Cancelar

```ts
const controller = new AbortController();
const { data } = await andco.rest.http.GET("/accounts", { signal: controller.signal });
controller.abort();
```

## Intents

Un Intent es una operación que Andco presenta por su cuenta. El cliente principal solo conoce el ciclo de vida neutro: `create(type, input, options)`, `get`, `execute`, `events`, `subscribe`. Crear un depósito, un retiro o un cargo automático es específico del dominio bancario y vive en el Bank Resource Server Definition — se vincula una vez a las credenciales vigentes y se usa desde ahí:

```ts
import { Bank } from "@andco/bank-sdk";

const bankDefinition = new Bank({ clientId, resource: "https://api.andco.cl" });
const bank = bankDefinition.use(andco);

const { data: intent } = await bank.intents.createDeposit<{ id: string }>({ amount: 25000 });
const { data: status } = await andco.intents.get<{ status: string }>(intent.id);
```

`bank.intents` también tiene `createWithdrawal`, `createAutomaticCharge`, `closeDeposit`, `getEvents` y `getAccountEvents` para el ciclo de vida bancario; `execute` sigue siendo neutro y vive en `andco.intents`.

El resultado autoritativo se lee con `get`, no del callback de la presentación: un mensaje puede perderse o llegar dos veces, y una lectura autenticada no.

## Eventos

```ts
const stop = bank.intents.onIntentDepositEvent({ intentId: intent.id, onError: reportError }, (event) => {
  update(event);
});
```

Devuelve la función para dejar de escuchar, igual que `onChange`.

## Sin sesión

Si no hay sesión, `rest` llama sin token y Andco responde `401`. El error trae el código y, cuando falta un permiso, el scope que hacía falta:

```ts
if (error?.details?.["required_scope"]) {
  await andco.auth.signIn({ scopes: [...session.scopes, String(error.details["required_scope"])] });
}
```

## Tu propio cliente, sin el SDK

Si solo quieres la API tipada —sin OAuth, sesión ni renovación— constrúyela directo con `createAndCoRestClient`:

```ts
import { createAndCoRestClient } from "@andco/protocol/transport";

const rest = createAndCoRestClient({ accessToken: () => miToken });
const { data, error } = await rest.GET("/accounts");
```

O sin ningún paquete de Andco, con `openapi-fetch` puro y los tipos generados:

```ts
import createClient from "openapi-fetch";
import type { AndCoRestPaths } from "@andco/protocol/transport";

const client = createClient<AndCoRestPaths>({ baseUrl: "https://api.andco.cl" });
client.use({
  async onRequest({ request }) {
    request.headers.set("Authorization", `Bearer ${miToken}`);
    return request;
  },
});
```

Es lo mismo que hace `createAndCoRestClient` por dentro: solo cambia quién resuelve el token.
