# Primeros pasos

Crea una llave, da de alta un cliente con su primera cuota y recibe un webhook cuando se pague.

Toma unos quince minutos. Los ejemplos usan `curl` y dos variables de entorno.

```sh
export MAKATEA_API=https://makatea.ai/api
export MAKATEA_KEY=mk_live_...
```

## 1. Saca una llave

En Makatea entra a **Configuración → Desarrolladores → Nueva llave**. Sólo el dueño o un administrador de la organización ve esa sección.

- Ponle el nombre del sistema que la va a usar.
- Elige los permisos. `read` consulta y `write` crea, cambia y borra.
- Copia la llave al crearla. Empieza con `mk_live_` y no se vuelve a mostrar.

Cada llamada lleva la llave en uno de estos encabezados.

```http
Authorization: Bearer mk_live_...
X-API-Key: mk_live_...
```

Comprueba que el servicio contesta. Esta ruta no pide llave.

```sh
curl -s $MAKATEA_API/v1/status
```

## 2. Da de alta un cliente

`external_ref` es tu identificador del cliente. Es único por organización y sirve para buscarlo después sin guardar el id de Makatea.

```sh
curl -s -X POST $MAKATEA_API/v1/members \
  -H "Authorization: Bearer $MAKATEA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: alta-cliente-1042" \
  -d '{
    "full_name": "Sofía Ramírez López",
    "phone_e164": "+5215512345678",
    "email": "sofia@ejemplo.mx",
    "external_ref": "CLI-1042",
    "identity": { "contrato": "PSG-1042" }
  }'
```

La respuesta trae el cliente dentro de `data`. Guarda `data.id` para el siguiente paso.

```json
{ "data": { "id": "6f1c…", "full_name": "Sofía Ramírez López", "external_ref": "CLI-1042", "state": "active" } }
```

Los campos de `identity` quedan disponibles como variables en las plantillas de mensaje.

## 3. Crea su primera cuota

Una cuota es un cobro con monto y fecha de vencimiento. Si la organización tiene un calendario de cobranza activo, la cuota entra a él y sus recordatorios se programan solos.

```sh
curl -s -X POST $MAKATEA_API/v1/billing-orders \
  -H "Authorization: Bearer $MAKATEA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cuota-CLI-1042-2026-10" \
  -d '{
    "member_id": "6f1c…",
    "amount": 1850,
    "due_date": "2026-10-10",
    "period_label": "Octubre 2026",
    "external_ref": "CLI-1042-2026-10"
  }'
```

Si la cuota es de un crédito, manda también `capital_portion` e `interest_portion`. Los dos van juntos y su suma no pasa de `amount`.

Para ver los recordatorios que quedaron programados:

```sh
curl -s "$MAKATEA_API/v1/sequence-runs?member_id=6f1c…" -H "Authorization: Bearer $MAKATEA_KEY"
```

## 4. Registra un pago

`paid_at` es el día en que entró el dinero. Puede ser pasado y nunca futuro. Un pago menor al saldo deja la cuota abierta con su abono.

```sh
curl -s -X POST $MAKATEA_API/v1/billing-orders/{id}/payments \
  -H "Authorization: Bearer $MAKATEA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pago-SPEI-4471" \
  -d '{ "amount": 1850, "paid_at": "2026-10-09", "method": "transfer", "reference": "SPEI-4471" }'
```

Al quedar pagada, la cuota sale del calendario y los recordatorios pendientes se cancelan.

## 5. Recibe webhooks

Registra un endpoint `https` con los eventos que te interesan, o `*` para todos.

```sh
curl -s -X POST $MAKATEA_API/v1/webhook-endpoints \
  -H "Authorization: Bearer $MAKATEA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://tu-sistema.mx/webhooks/makatea",
    "events": ["billing_order.paid", "payment.received", "promise.broken"]
  }'
```

La respuesta trae el secreto de firma `whsec_…` una sola vez. Guárdalo junto a la llave.

Cada evento llega como `POST` con este cuerpo.

```json
{ "id": "evt…", "type": "payment.received", "created_at": "2026-10-09T15:02:11Z", "data": { } }
```

Verifica la firma antes de confiar en el cuerpo. El encabezado `Makatea-Signature` trae `t` (segundos Unix) y `v1`, el HMAC-SHA256 de `t + "." + cuerpo crudo` con tu secreto.

```js
import crypto from "node:crypto";

// cuerpoCrudo: el cuerpo tal como llegó, antes de JSON.parse.
export function firmaValida(secreto, encabezado, cuerpoCrudo) {
  const partes = Object.fromEntries(encabezado.split(",").map((p) => p.trim().split("=")));
  const t = Number(partes.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const esperado = crypto.createHmac("sha256", secreto).update(`${t}.${cuerpoCrudo}`).digest("hex");
  const a = Buffer.from(esperado);
  const b = Buffer.from(partes.v1 ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
```

Contesta con un `2xx` en menos de 10 segundos. Si no, Makatea reintenta a 1 min, 5 min, 30 min, 2 h, 6 h y 24 h. Tras 8 intentos la entrega queda `failed` y se reintenta con `POST /v1/webhook-deliveries/{id}/retry`.

Un evento puede llegar dos veces o fuera de orden. Usa `id` para descartar el repetido.

## Errores que vas a ver

Todo error trae la misma forma, con un `request_id` para pedir soporte.

```json
{ "error": { "code": "validation_error", "message": "amount must be a positive number", "request_id": "…" } }
```

| Código | Cuándo pasa | Qué hacer |
|---|---|---|
| `401` | Falta la llave o no es válida | Revisa el encabezado y que la llave no esté revocada |
| `403 insufficient_scope` | La llave no tiene el permiso | Crea una llave con `write` |
| `409` | El `external_ref` ya existe o la cuota ya está pagada | Busca el registro con `?external_ref=` |
| `422 idempotency_key_reused` | Misma `Idempotency-Key` con otro cuerpo | Usa una llave nueva por operación |
| `429` | Pasaste de 600 llamadas por minuto | Espera lo que diga `Retry-After` |

## Siguiente

- [Carga histórica](https://makatea.ai/desarrolladores/guias/carga-historica) para subir tu cartera actual.
- [Conciliación diaria](https://makatea.ai/desarrolladores/guias/conciliacion-diaria) para cuadrar los pagos contra tu sistema.
- [Referencia completa](https://makatea.ai/desarrolladores/referencia) con cada ruta y cada campo.
