Saltearse al contenido

Autenticación

La API no usa una sola credencial. La sesión del panel y el token de sitio comparten el guard de Sanctum, pero representan cosas distintas: un usuario y una integración. Cada ruta declara cuál acepta y qué más exige.

No todas piden credencial: el catálogo público (/api/catalog/*), el manifiesto, la agenda pública y los webhooks van sin token.

POST /api/login recibe email y password y devuelve token y user (id, name, email, is_staff, email_verified). El token se llama admin-panel, lleva la habilidad * y vence a los 7 días. Se manda como Bearer.

POST /api/logout borra el token con el que llamas. Las rutas del panel llevan auth:sanctum; su grupo añade panel.token, que impide que un token del área de cliente abra el panel. Sin token, vencido o inválido, la respuesta es 401.

Es la credencial de una integración con un sitio concreto. Se emite con POST /api/sites/{site}/tokens, que exige name y abilities; expires_at es opcional y tiene que ser futuro. Sin expires_at, el token vence a los 90 días (Site::TOKEN_DEFAULT_TTL_DAYS).

La respuesta trae el token en claro una sola vez, en token y plain_text_token: la base guarda un hash. GET /api/sites/{site}/tokens lista los tokens y devuelve el abilities_catalog; DELETE /api/sites/{site}/tokens/{token} revoca, salvo el token con el que estás llamando (422).

Autentica como un Site, no como un User: una sesión de panel no sirve en estas rutas.

Site::TOKEN_ABILITIES declara trece: track, leads, catalog, blog, project-log, certifications, integrations, training, orders, site, pages, fiscal y documents. * es la llave maestra y se rechaza mezclada con habilidades concretas.

La habilidad no elige el módulo: cada ruta declara las dos cosas.

Las rutas de token de Sitio que abren un módulo llevan:

  • module:<clave>: el sitio tiene el módulo y su estado de acceso lo permite (FeatureAccess::allows). Si no, 403 con module.
  • token.ability:<habilidad>: la credencial tiene la habilidad. Si no, 403 con ability.

Ejemplos: GET /api/site/pages (module:pages + token.ability:pages), GET /api/blog/posts (module:blog + token.ability:blog), POST /api/orders (module:pedidos + token.ability:orders).

La excepción documentada es GET /api/site: solo token.ability:site. Devuelve una lista blanca —contacto, marca y logo—, sin plan, vigencias, datos fiscales ni configuración del agente. No lleva módulo a propósito: no existe un módulo «tener nombre y teléfono», y exigir uno dejaría a un plan quitarle el pie de página a un cliente.

Dos detalles:

  • POST /api/leads y POST /api/track aceptan token de sitio o clave de ingest (site_key en el cuerpo, en la query o en X-Merez-Ingest-Key). La habilidad se comprueba al resolver la credencial (ResolvesSiteCredential). Sin ninguna, /leads responde 422, no 401.
  • El 403 de módulo y el de habilidad se distinguen por module o ability en el cuerpo.
Ventana de terminal
# 1. Login del panel
curl -s -X POST https://api.merez.co/api/v1/login \
-H 'Content-Type: application/json' \
-d '{"email":"dueno@negocio.co","password":"..."}'
# 2. Emitir un token de sitio
curl -s -X POST https://api.merez.co/api/v1/sites/12/tokens \
-H "Authorization: Bearer $PANEL" \
-H 'Content-Type: application/json' \
-d '{"name":"Fusion","abilities":["catalog","blog"]}'
# 3. Usarlo
curl -s https://api.merez.co/api/v1/blog/posts \
-H "Authorization: Bearer $SITE"

Si al token le falta la habilidad:

{"message":"El token no tiene la habilidad 'blog'.","ability":"blog"}
  • Rotar sin ventana. Revocar un token corta la integración en el acto: no hay período de gracia. Emite el nuevo, despliega y después revoca el viejo.
  • Perder el texto en claro. Solo se muestra al emitirlo. Si se pierde, se revoca y se emite otro.
  • Un token sin la habilidad. La integración funciona hasta que toca la ruta que la exige; entonces llega el 403 con ability. Revisa el catálogo antes.
  • Apagar un módulo. El 403 llega con module y las rutas de ese módulo dejan de responder, aunque el token siga vivo.
  • Mezclar * con habilidades concretas. ["*","blog"] se rechaza con 422: la llave maestra no se disfraza de credencial acotada.
  • Convertir la excepción de GET /site en regla. Un token con site lee contacto y marca aunque el sitio no tenga módulos. Es deliberado; no le añadas un módulo.
  • Contrato: qué claves devuelve cada Resource.
  • Errores: qué significa cada 401, 403 y 422.
  • Versionado: qué versión de la API estás consumiendo.