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.

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.

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

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

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.

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.

{ "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.

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:

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.

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.

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.

{ "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.

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.

{ "error": { "code": "validation_error", "message": "amount must be a positive number", "request_id": "…" } }
CódigoCuándo pasaQué hacer
401Falta la llave o no es válidaRevisa el encabezado y que la llave no esté revocada
403 insufficient_scopeLa llave no tiene el permisoCrea una llave con write
409El external_ref ya existe o la cuota ya está pagadaBusca el registro con ?external_ref=
422 idempotency_key_reusedMisma Idempotency-Key con otro cuerpoUsa una llave nueva por operación
429Pasaste de 600 llamadas por minutoEspera lo que diga Retry-After

Siguiente

Esta guía en markdown. Sigue con Carga histórica.