> ## Documentation Index
> Fetch the complete documentation index at: https://docs.edtools.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Inicio rápido

> De cero a la primera llamada autenticada, y qué mirar antes de escribir la integración.

El Client API es la superficie estable de EdTools para integraciones server-to-server: un SIS que sincroniza estudiantes, una tesorería que empuja pagos, un CRM que lee admisiones.

<Info>
  **Base**: `https://app.edtools.co/api/client/v1` · **41 operaciones** en 8 recursos · OpenAPI 3.1 en [`/api/client/openapi.json`](https://app.edtools.co/api/client/openapi.json)
</Info>

## Requisitos

<Steps>
  <Step title="El Client API está encendido en el entorno">
    `EDTOOLS_CLIENT_API_ENABLED=1`. Para webhooks, además `EDTOOLS_CLIENT_WEBHOOKS_ENABLED=1`.
  </Step>

  <Step title="La institución tiene el módulo de integraciones">
    `platform_integrations` activo, más el [módulo funcional](/plataforma/modulos) del recurso que vas a tocar. Sin esto los endpoints responden `403 MODULE_DISABLED`.
  </Step>

  <Step title="Tienes una API key">
    Se crea en **Ajustes → API e integraciones → API Keys**. Necesitas el permiso `settings.api.manage`.
  </Step>
</Steps>

## Tu primera llamada

```bash theme={null}
curl https://app.edtools.co/api/client/v1/me \
  -H "Authorization: Bearer $EDTOOLS_API_KEY"
```

```json theme={null}
{
  "data": {
    "tenant": { "id": "...", "slug": "colegio-abc", "name": "Colegio ABC" },
    "apiKey": {
      "id": "...",
      "name": "SIS producción",
      "scopes": ["students:read", "students:write"],
      "masterDomains": ["students"],
      "rateLimit": { "requestsPerMinute": 120 }
    },
    "productAccess": {
      "enabledModules": ["platform_integrations", "staff_students"],
      "sorByDomain": { "students": "external_master", "grades": "edtools_master" }
    }
  }
}
```

<Tip>
  `/me` es la llamada de diagnóstico. Antes de depurar un `403`, mira qué te responde: casi siempre la respuesta está ahí — falta un scope, falta un módulo, o el dominio no es tuyo.
</Tip>

## Qué puedes tocar

| Recurso    | Operaciones | Scopes                                |
| ---------- | ----------- | ------------------------------------- |
| Students   | 5           | `students:read`, `students:write`     |
| Admissions | 9           | `admissions:read`, `admissions:write` |
| Payments   | 5           | `payments:read`, `payments:write`     |
| Vault      | 15          | `vault:read`, `vault:write`           |
| Programs   | 2           | `programs:read`                       |
| Courses    | 2           | `courses:read`                        |
| Forms      | 2           | `forms:read`                          |
| Client API | 1           | — (`/me`)                             |

## Las convenciones que se repiten

<AccordionGroup>
  <Accordion title="Todo viene envuelto en data">
    Las respuestas de éxito llevan la carga en `data`. Los errores llevan `error` con `code`, `message` y `requestId`.
  </Accordion>

  <Accordion title="Los listados se paginan con page y limit">
    Y aceptan `updatedSince` para sincronización incremental. Pide solo lo que cambió desde tu última corrida.
  </Accordion>

  <Accordion title="Los POST exigen Idempotency-Key">
    Reintentar sin ella duplica recursos. Ver [Idempotencia](/client-api/idempotencia).
  </Accordion>

  <Accordion title="Los PUT /external/{externalId} son upserts">
    Si tu sistema ya tiene un identificador estable, úsalo: sincronizas sin crear duplicados y sin llevar cuenta de los ids de EdTools.
  </Accordion>

  <Accordion title="Las escrituras respetan el Source of Record">
    Un `403 SOR_WRITE_FORBIDDEN` no es un problema de permisos del token, es que ese dominio de datos tiene otro dueño. Ver [Multi-tenancy](/plataforma/multi-tenant).
  </Accordion>
</AccordionGroup>

## Con el SDK, en tres líneas

```ts theme={null}
import { EdToolsClient } from '@edtools/client';

const edtools = new EdToolsClient({
  baseUrl: 'https://app.edtools.co',
  apiKey: process.env.EDTOOLS_API_KEY!,
});

const estudiantes = await edtools.students.list({ limit: 20 });
```

Sigue por [Autenticación](/client-api/autenticacion) si vas a configurar el token con cuidado, o por el [SDK](/client-api/sdk) si trabajas en TypeScript.
