# API de Clatri

URL: https://docs.clatri.com/api/

> Usa la API REST de Clatri desde tus apps y scripts: crea el token, haz tu primera llamada, permisos, idempotencia, errores, límites y seguridad.

La **API de Clatri** te deja leer y modificar tus datos de Clatri desde tus propias apps, scripts y automatizaciones, con HTTPS y JSON. Ejecuta las **mismas herramientas** que usan el agente de Clatri y el [Clatri MCP](https://docs.clatri.com/mcp/): registrar un gasto, consultar el estado de resultados, crear una tarea, leer tus medicamentos…

Usa el **mismo token** que el MCP. Si ya tienes uno, no necesitas otra llave.

:::tip ¿API o MCP?
- **MCP**: si quieres que un asistente de IA (Claude, ChatGPT, Cursor…) consulte tu Clatri mientras conversas con él. Ver [Clatri MCP](https://docs.clatri.com/mcp/).
- **API**: si escribes código. Tu programa decide qué herramienta llamar y con qué datos, y recibe JSON.
:::

---

## Cómo funciona {#how-it-works}

- **URL base:** `https://api.clatri.com/v1`
- **Autenticación:** cabecera `Authorization: Bearer clt_mcp_XXXX` en cada llamada.
- **Todo es una herramienta.** Para ejecutar una, haces `POST` a `/v1/entities/{entity_id}/tools/{tool_name}` con sus argumentos como cuerpo JSON. La entidad (personal, empresa, proyecto) siempre va en la ruta.

| Método y ruta | Para qué sirve |
| --- | --- |
| `GET /v1/me` | El token: tu usuario, permisos, áreas, entidades y fecha de caducidad. |
| `GET /v1/entities` | Las entidades que este token puede usar (id, tipo, nombre). |
| `GET /v1/tools` | Las herramientas que **este token** puede llamar, con su esquema de entrada. |
| `POST /v1/entities/{entity_id}/tools/{tool_name}` | Ejecuta una herramienta en esa entidad. |
| `GET /v1/openapi.json` | La especificación OpenAPI 3.1 completa. Es pública: no necesita token. |

La lista completa de herramientas, con sus argumentos, está en la [referencia de la API](https://docs.clatri.com/api/reference/).

---

## Requisitos {#requirements}

<details>
<summary>Necesitas una suscripción activa de Clatri</summary>

Igual que el MCP, la API requiere una suscripción activa. Sin ella no puedes crear tokens, y los que ya existen responden `402 subscription_inactive` hasta que la renueves. No se borran: vuelven a funcionar solos al renovar.

<details>
<summary>Necesitas llamarla desde un servidor o un script</summary>

La API no acepta llamadas desde el navegador: no envía cabeceras CORS. Es a propósito, para que nadie ponga tu token en el código de una página web. Llámala desde un backend, un script, una función serverless o una herramienta de automatización.

---

## Paso 1 — Crea tu token {#create-token}

1. En la app de Clatri, abre **Ajustes** → **Conexiones** → **Agentes y APIs**. En la web, **Ajustes** → **Agentes y APIs**.
2. Toca **Crear token** y ponle un nombre que reconozcas (por ejemplo, "Mi script de gastos").
3. Elige los **permisos**: **Solo lectura**, **Lectura y escritura** o **Acceso completo** (incluye eliminar).
4. Si quieres, limita las **áreas** (Dinero, Salud, Administración, General) y las **entidades** que puede usar. Por defecto tiene todas.
5. Toca **Crear token** y cópialo.

:::warning Cópialo de inmediato
El token (empieza por `clt_mcp_`) se muestra **una sola vez**. Si lo pierdes, revócalo y crea otro. Trátalo como una contraseña: cualquiera que lo tenga puede usar tus datos con los permisos que elegiste.
:::

Los tokens caducan a los 6 meses y puedes tener hasta 10 activos. Después de creado, puedes cambiar su nombre, permisos, áreas y entidades sin generar uno nuevo.

En los ejemplos de esta página el token está en una variable de entorno:

```bash
export CLATRI_TOKEN="clt_mcp_XXXX"
```

---

## Paso 2 — Tu primera llamada {#first-call}

Comprueba que el token funciona con `GET /v1/me`:

```bash
curl https://api.clatri.com/v1/me \
  -H "Authorization: Bearer $CLATRI_TOKEN"
```

```python
import os
import requests

BASE = "https://api.clatri.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['CLATRI_TOKEN']}"}

me = requests.get(f"{BASE}/me", headers=HEADERS, timeout=30)
me.raise_for_status()
print(me.json())
```

```js
// Node.js 18 o superior (fetch incluido)
const BASE = "https://api.clatri.com/v1";
const headers = { Authorization: `Bearer ${process.env.CLATRI_TOKEN}` };

const res = await fetch(`${BASE}/me`, { headers });
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
console.log(await res.json());
```

La respuesta se ve así (datos ficticios):

```json
{
  "user_id": "11111111-1111-4111-8111-111111111111",
  "credential": "personal_token",
  "token_name": "Mi script de gastos",
  "permissions": ["read", "write"],
  "areas": ["money", "administration"],
  "entity_ids": null,
  "entities": [
    {"id": "22222222-2222-4222-8222-222222222222", "type": "personal", "name": "Personal", "is_shared": false},
    {"id": "33333333-3333-4333-8333-333333333333", "type": "business", "name": "Mi empresa", "is_shared": false}
  ],
  "expires_at": "2027-04-29T15:00:00+00:00",
  "request_id": "req_0f1e2d3c4b5a69788796a5b4c3d2e1f0"
}
```

- `areas: null` significa todas las áreas; `entity_ids: null`, todas tus entidades.
- `is_shared: true` marca una entidad que otra persona compartió contigo.

### Elige la entidad {#choose-entity}

`GET /v1/entities` devuelve solo la lista de entidades del token. Guarda el `id` de la que vas a usar:

```bash
curl https://api.clatri.com/v1/entities \
  -H "Authorization: Bearer $CLATRI_TOKEN"
```

```json
{
  "entities": [
    {"id": "22222222-2222-4222-8222-222222222222", "type": "personal", "name": "Personal", "is_shared": false}
  ],
  "request_id": "req_…"
}
```

### Descubre las herramientas {#discover-tools}

`GET /v1/tools` lista lo que **este token** puede hacer: ya filtra por sus permisos y áreas. Cada herramienta trae su esquema de entrada (JSON Schema):

```bash
curl https://api.clatri.com/v1/tools \
  -H "Authorization: Bearer $CLATRI_TOKEN"
```

```json
{
  "tools": [
    {
      "name": "create_task",
      "title": "Create task",
      "description": "Create a task. …",
      "area": "administration",
      "permission": "write",
      "destructive": false,
      "supports_dry_run": false,
      "requires_confirmation": false,
      "requires_idempotency_key": true,
      "path": "/v1/entities/{entity_id}/tools/create_task",
      "input_schema": {"type": "object", "properties": {"title": {"type": "string"}}, "required": ["title"]}
    }
  ],
  "request_id": "req_…"
}
```

Los nombres, descripciones y esquemas de las herramientas están en inglés.

---

## Paso 3 — Ejecuta una herramienta {#call-a-tool}

### Una lectura {#read-example}

Estado de resultados de septiembre de 2026 (lo ganado y lo gastado) en la entidad personal:

```bash
curl -X POST \
  https://api.clatri.com/v1/entities/22222222-2222-4222-8222-222222222222/tools/read_income_statement \
  -H "Authorization: Bearer $CLATRI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"start_date": "2026-09-01", "end_date": "2026-09-30", "include_analytics": false}'
```

```python
ENTITY = "22222222-2222-4222-8222-222222222222"

res = requests.post(
    f"{BASE}/entities/{ENTITY}/tools/read_income_statement",
    headers=HEADERS,
    json={"start_date": "2026-09-01", "end_date": "2026-09-30", "include_analytics": False},
    timeout=60,
)
res.raise_for_status()
body = res.json()
print(body["text"])
```

```js
const ENTITY = "22222222-2222-4222-8222-222222222222";

const res = await fetch(`${BASE}/entities/${ENTITY}/tools/read_income_statement`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ start_date: "2026-09-01", end_date: "2026-09-30", include_analytics: false }),
});
const body = await res.json();
console.log(body.text);
```

Toda respuesta correcta tiene la misma forma:

```json
{
  "data": {"…": "resultado estructurado, cuando la herramienta devuelve JSON"},
  "text": "La respuesta de la herramienta en texto",
  "request_id": "req_6c1d0e2a9b7f4e3c8a5d1f0b2e4c6a8d",
  "idempotent_replay": false
}
```

| Campo | Qué contiene |
| --- | --- |
| `data` | El resultado en JSON cuando la herramienta lo devuelve. Si la herramienta solo responde con texto, es `null`. |
| `text` | La respuesta completa de la herramienta, en texto. Siempre está. |
| `request_id` | El identificador de la llamada. También llega en la cabecera `Clatri-Request-Id`. Inclúyelo si escribes a soporte. |
| `idempotent_replay` | `true` cuando es la respuesta guardada de una llamada anterior con la misma `Idempotency-Key` (ver abajo). |

:::note
No envíes `entity_id` en el cuerpo: va en la ruta. Un argumento que la herramienta no conoce también se rechaza con `400 validation_error`, antes de ejecutar nada.
:::

### Una escritura {#write-example}

Las herramientas que crean, editan o eliminan exigen la cabecera `Idempotency-Key`. Crear una tarea en la entidad personal:

```bash
curl -X POST \
  https://api.clatri.com/v1/entities/22222222-2222-4222-8222-222222222222/tools/create_task \
  -H "Authorization: Bearer $CLATRI_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5b0d7f8e-3c2a-4e1b-9f6d-1a2b3c4d5e6f" \
  -d '{"title": "Renovar el seguro del carro", "due_date": "2026-11-15"}'
```

```python
import uuid

res = requests.post(
    f"{BASE}/entities/{ENTITY}/tools/create_task",
    headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
    json={"title": "Renovar el seguro del carro", "due_date": "2026-11-15"},
    timeout=60,
)
res.raise_for_status()
print(res.json()["text"])
```

```js
const res = await fetch(`${BASE}/entities/${ENTITY}/tools/create_task`, {
  method: "POST",
  headers: {
    ...headers,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({ title: "Renovar el seguro del carro", due_date: "2026-11-15" }),
});
console.log((await res.json()).text);
```

---

## Permisos, áreas y entidades {#permissions}

Cada token tiene tres límites. Una llamada que se sale de cualquiera de ellos se rechaza antes de ejecutar nada.

**Permisos.** Cada herramienta pide un permiso:

| Permiso en la API | Qué permite | Nivel en la app que lo incluye |
| --- | --- | --- |
| `read` | Consultar | Solo lectura, Lectura y escritura, Acceso completo |
| `write` | Crear y editar | Lectura y escritura, Acceso completo |
| `delete` | Eliminar o anular | Acceso completo |

Sin el permiso → `403 scope_denied`.

**Áreas.** Cada herramienta pertenece a un área:

| Área en la app | En la API | Qué incluye |
| --- | --- | --- |
| Dinero | `money` | Cuentas, tarjetas, movimientos, deudas, ahorros, inversiones, ventas y contabilidad |
| Salud | `health` | Afecciones, episodios, medicamentos, fórmulas, métricas y documentos de salud |
| Administración | `administration` | Espacios, páginas, tableros, tareas, hábitos, calendario, contactos y lugares |
| General | `general` | Contexto, memoria, documentos, programaciones y actividad |

Fuera de las áreas del token → `403 domain_denied`.

**Entidades.** Si limitaste el token a algunas entidades, cualquier otra responde `403 entity_denied`. Lo mismo pasa si el cuerpo menciona un registro (una cuenta, una tarea…) de otra entidad.

:::tip Dale a cada integración solo lo que necesita
Un script que solo lee gastos no necesita escribir ni ver tu salud. Crea un token **Solo lectura**, con el área **Dinero** y la entidad que corresponda. Si algún día se filtra, el daño queda acotado.
:::

---

## Escrituras seguras {#safe-writes}

### Idempotency-Key {#idempotency}

Las herramientas con permiso `write` o `delete` exigen la cabecera `Idempotency-Key`. Sin ella → `400 idempotency_key_required`.

Genera un valor único por operación (un UUID sirve; de 1 a 255 caracteres ASCII visibles) y **reutilízalo si repites esa misma operación**, por ejemplo tras un corte de red. Así un reintento no registra el gasto dos veces:

| Situación | Resultado |
| --- | --- |
| Misma clave y mismo cuerpo, la primera llamada ya terminó | Recibes la respuesta guardada, con `idempotent_replay: true`. No se ejecuta otra vez. |
| Misma clave con otro cuerpo, otra herramienta u otra entidad | `409 idempotency_key_reused` |
| Misma clave mientras la primera llamada sigue en curso | `409 idempotency_in_progress`, con `Retry-After` |

- Una clave vale para el token que la usó y se recuerda durante 24 horas.
- Si la primera llamada terminó con un error del servidor (5xx), la clave se libera y puedes reintentar con la misma.
- Las lecturas no necesitan clave.

### Vista previa con `?dry_run=true` {#dry-run}

Algunas herramientas pueden mostrarte el resultado **sin guardar nada**. Son las que en `GET /v1/tools` tienen `supports_dry_run: true`. Agrega `?dry_run=true` a la URL:

```bash
curl -X POST \
  "https://api.clatri.com/v1/entities/22222222-2222-4222-8222-222222222222/tools/record_consumable_balance_observation?dry_run=true" \
  -H "Authorization: Bearer $CLATRI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"balance_identifier": "Tarjeta de transporte", "observed_amount": 25000, "source": "api"}'
```

- Con `?dry_run=true` la herramienta solo calcula (`preview: true`), aunque el cuerpo diga otra cosa.
- Una vista previa no necesita `Idempotency-Key` y su respuesta no se guarda.
- En una herramienta sin vista previa, `?dry_run=true` responde `400 dry_run_not_supported`: nunca se ejecuta "de verdad" por error.

### Confirmar borrados con `?confirm=true` {#confirm}

Las herramientas con permiso `delete` (eliminar o anular datos) exigen `?confirm=true` en la URL, además de la `Idempotency-Key`. Sin la confirmación → `428 confirmation_required` y no se borra nada:

```bash
curl -X POST \
  "https://api.clatri.com/v1/entities/22222222-2222-4222-8222-222222222222/tools/delete_task?confirm=true" \
  -H "Authorization: Bearer $CLATRI_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9e8d7c6b-5a49-4382-9170-6f5e4d3c2b1a" \
  -d '{"task_id": "44444444-4444-4444-8444-444444444444"}'
```

En `GET /v1/tools` estas herramientas tienen `requires_confirmation: true`. El campo `destructive: true` marca además las que sobrescriben datos.

---

## Errores {#errors}

Los errores llegan como `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)), siempre con un `code` estable que puedes usar en tu código:

```json
{
  "type": "https://docs.clatri.com/api/errors#scope_denied",
  "title": "Permission not granted",
  "status": 403,
  "detail": "This token does not have the permission this tool requires.",
  "code": "scope_denied",
  "request_id": "req_6c1d0e2a9b7f4e3c8a5d1f0b2e4c6a8d"
}
```

`title` y `detail` están en inglés y pueden cambiar de redacción: decide con `code` y `status`.

| HTTP | Códigos |
| --- | --- |
| 400 | `validation_error`, `idempotency_key_required`, `dry_run_not_supported`, `https_required` |
| 401 | `unauthorized`, `token_revoked`, `token_expired` |
| 402 | `subscription_inactive` |
| 403 | `scope_denied`, `domain_denied`, `entity_denied` |
| 404 | `tool_not_found`, `tool_not_available`, `not_found` |
| 405 | `method_not_allowed` |
| 409 | `idempotency_key_reused`, `idempotency_in_progress` |
| 413 | `payload_too_large` |
| 422 | `tool_error` |
| 428 | `confirmation_required` |
| 429 | `rate_limited` |
| 500 | `internal_error` |
| 503 | `service_unavailable` |

Qué significa cada código y qué hacer: [Errores de la API](https://docs.clatri.com/api/errors/).

`422 tool_error` es el más común en el día a día: la herramienta se ejecutó pero no pudo completar lo que pediste (por ejemplo, una cuenta que no existe). El `detail` explica el motivo.

---

## Límites {#limits}

| Límite | Valor |
| --- | --- |
| Lecturas por token | 120 por minuto |
| Escrituras y borrados por token | 30 por minuto |
| Llamadas por entidad (todos los tokens juntos) | 300 por minuto |
| Tamaño máximo del cuerpo | 256 KB |

- Las ventanas son de un minuto fijo. `GET /v1/me`, `/v1/entities` y `/v1/tools` cuentan como lecturas del token.
- Las respuestas traen `RateLimit-Limit`, `RateLimit-Remaining` y `RateLimit-Reset` (segundos hasta que se reinicia la ventana). Si aplican varios límites, las cabeceras muestran el más cercano a agotarse.
- Al pasarte recibes `429 rate_limited` con `Retry-After` en segundos. Espera ese tiempo antes de reintentar.
- **Bloqueo por fallos repetidos:** 20 respuestas `401` o `403` en 5 minutos, para un mismo token o una misma IP, bloquean ese token o esa IP durante 15 minutos (`429` con `Retry-After`). Si tu script recibe un `401` o un `403`, corrige la causa en lugar de reintentar en bucle.
- Algunas herramientas (búsqueda web, mapas, imágenes) consumen créditos de tu cuenta, como cuando las usa el agente.

---

## Cabeceras útiles {#headers}

| Cabecera | Dónde | Para qué |
| --- | --- | --- |
| `Authorization: Bearer …` | Petición | Tu token. Obligatoria salvo en `/v1/openapi.json`. |
| `Idempotency-Key` | Petición | Obligatoria en escrituras y borrados. |
| `Content-Type: application/json` | Petición | En las llamadas con cuerpo. |
| `Clatri-Request-Id` | Respuesta | Identificador de la llamada, en todas las respuestas. |
| `RateLimit-*`, `Retry-After` | Respuesta | Límites de tasa (ver arriba). |

La API solo funciona por HTTPS. Las respuestas llevan `Cache-Control: no-store`.

---

## Versionado y deprecación {#versioning}

- La versión va en la ruta: `/v1`. Un cambio que rompa la compatibilidad sale como una versión nueva.
- Antes de retirar una versión, sus respuestas llevan las cabeceras `Deprecation` y `Sunset`, con al menos **90 días** de aviso.
- Los códigos de error son parte del contrato: pueden aparecer códigos nuevos, pero los existentes no se renombran ni se eliminan dentro de `v1`.
- Las herramientas son las mismas del agente de Clatri, así que el catálogo crece con el producto. Consulta `GET /v1/tools` o la [referencia](https://docs.clatri.com/api/reference/) para ver el esquema vigente.

---

## Seguridad {#security}

<details>
<summary>Cuida tu token</summary>

- **Nunca lo compartas** ni lo pegues en chats, capturas, tickets o foros.
- **No lo subas a un repositorio** ni lo pongas en el código de una app móvil o una página web. Guárdalo en una variable de entorno o en un gestor de secretos.
- **Un token por integración.** Así puedes revocar uno sin afectar a los demás y ves en la actividad qué hizo cada uno.
- **Si se filtró, revócalo** en Ajustes → Conexiones → Agentes y APIs. La revocación es inmediata. Luego crea otro.

<details>
<summary>Qué puede y qué no puede hacer un token</summary>

Un token solo actúa dentro de Clatri, con los permisos, áreas y entidades que le diste. **No puede** crear otros tokens, cambiar tu contraseña o tu correo, tocar tu suscripción, borrar una entidad ni ver entidades fuera de su alcance.

Cada llamada a una herramienta queda en la actividad reciente del token (Ajustes → Conexiones → Agentes y APIs → toca el token), igual que las del MCP. Si ves algo que no reconoces, revócalo.

<details>
<summary>Herramientas que no están disponibles por API</summary>

Algunas herramientas del agente no se pueden llamar por la API aunque el token tenga permiso. Responden `404 tool_not_available` y no aparecen en `GET /v1/tools` ni en la referencia:

- **Consultas libres a la base de datos.** No son un contrato estable ni revisable.
- **Contraseñas de documentos.** Guardar o usar la contraseña de un PDF protegido es manejo de credenciales.
- **Gestión de accesos.** Invitar o quitar miembros de un espacio, ver quién más está en él, o vincular un contacto con otra cuenta de Clatri: cambian quién ve tus datos.
- **Buscar otras entidades o personas.** Un token nunca ve entidades fuera de las suyas.
- **Programaciones.** Crear, editar o ejecutar una programación pone a trabajar después al agente completo con todos tus permisos, por fuera de los límites del token.
- **`whoami` y `list_entities`** del MCP: en la API los reemplazan `GET /v1/me` y `GET /v1/entities`.

Para estas acciones usa la app o el chat de Clatri.

<details>
<summary>Si conectas la API a un modelo de IA</summary>

Lo que devuelve la API son tus datos: descripciones de movimientos, textos de documentos, notas. Si se los pasas a un modelo de IA, trátalos como datos, no como instrucciones. Un texto dentro de un documento podría intentar darle órdenes al modelo.

<details>
<summary>Tokens OAuth de apps conectadas</summary>

Además de los tokens personales (`clt_mcp_`), la API acepta los tokens de acceso OAuth (`clt_at_`) que reciben las apps a las que conectaste Clatri por OAuth. Esos tokens solo ven el catálogo reducido de herramientas que esas apps usan en el MCP.

---

## Referencia de la API {#reference}

- **[Referencia interactiva](https://docs.clatri.com/api/reference/)**: todas las herramientas, con sus argumentos, permisos, áreas y ejemplos de cuerpo.
- **OpenAPI 3.1:** `https://api.clatri.com/v1/openapi.json` (pública, siempre al día). Impórtala en Postman, Insomnia o tu generador de clientes.
- **[Errores de la API](https://docs.clatri.com/api/errors/)**: cada código, su causa y qué hacer.
