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

# SDK de TypeScript

> El paquete @edtools/client — qué te resuelve y cómo se usa.

Si integras desde Node o TypeScript, usa el SDK. Vive en `packages/client` y se encarga de lo repetitivo: la URL base, la cabecera de autorización, los parámetros de consulta, el timeout, y convertir los errores en excepciones tipadas.

## Empezar

```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,
  updatedSince: '2026-05-01T00:00:00.000Z',
});
```

El constructor acepta:

| Opción         | Para qué                                                                                                 |
| -------------- | -------------------------------------------------------------------------------------------------------- |
| `baseUrl`      | Origen de EdTools, **sin** `/api/client/v1`. El SDK lo agrega.                                           |
| `apiKey`       | El token de servicio.                                                                                    |
| `authProvider` | Alternativa a `apiKey`: un objeto con `getAccessToken()`. Reservado para un `client_credentials` futuro. |
| `fetch`        | Tu propio `fetch`, para tests o para un agente HTTP con proxy.                                           |
| `timeoutMs`    | Tope por petición.                                                                                       |

## Lo que cubre

<CardGroup cols={2}>
  <Card title="me()" icon="id-card">
    `edtools.me()` — tenant, scopes, módulos y Source of Record.
  </Card>

  <Card title="students" icon="user">
    `list`, `get`, `create`, `update`, `upsertExternal`.
  </Card>

  <Card title="admissions" icon="inbox">
    `pipeline.statuses.list`, `applications.*` con sus contactos.
  </Card>

  <Card title="payments" icon="credit-card">
    `list`, `get`, `create`, `update`, `upsertExternal`.
  </Card>

  <Card title="programs · courses" icon="book">
    Catálogos de solo lectura.
  </Card>

  <Card title="forms" icon="clipboard">
    `templates.list`, `submissions.list`.
  </Card>

  <Card title="vault" icon="folder">
    Tipos de documento, documentos, versiones, cargas y solicitudes.
  </Card>

  <Card title="webhooks" icon="signature">
    `verifyEdToolsWebhook`, `signEdToolsWebhook`.
  </Card>
</CardGroup>

## Crear exige la clave de idempotencia

No es opcional a nivel de tipos: en los `create`, el segundo argumento pide `idempotencyKey`. Si lo olvidas, no compila.

```ts theme={null}
const creado = await edtools.students.create(
  {
    externalId: 'sis-1001',
    email: 'ada@example.edu',
    name: 'Ada Lovelace',
    studentCode: 'S-1001',
  },
  { idempotencyKey: 'sis-1001-create' },
);
```

## Sincronizar con upsert

La forma recomendada cuando tu sistema ya tiene identificadores propios — sin llevar un mapa de ids de EdTools y sin riesgo de duplicar:

```ts theme={null}
await edtools.students.upsertExternal('sis-1001', {
  email: 'ada@example.edu',
  name: 'Ada Lovelace',
  studentCode: 'S-1001',
});
```

## Manejar errores

Los errores de la API se lanzan como `EdToolsApiError`, con el código público, el mensaje y el `requestId`:

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

try {
  await edtools.students.create(datos, { idempotencyKey: clave });
} catch (error) {
  if (error instanceof EdToolsApiError) {
    if (error.code === 'RATE_LIMITED') return reencolar();
    if (error.code === 'SOR_WRITE_FORBIDDEN') return avisarAOperaciones(error.requestId);
    throw error;
  }
  throw error;
}
```

Ver el [catálogo de códigos](/client-api/errores) para saber cuáles vale la pena reintentar y cuáles no.

## Verificar webhooks

El mismo paquete trae el verificador, así no reimplementas el HMAC:

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

const resultado = verifyEdToolsWebhook({
  secret: process.env.EDTOOLS_WEBHOOK_SECRET!,
  rawBody,
  headers: request.headers,
});

if (!resultado.ok) throw new Error(resultado.reason);
```

Ver [Webhooks](/client-api/webhooks) para las tres trampas clásicas (cuerpo crudo, comparación en tiempo constante, ventana de tolerancia).
