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.
Cómo funciona
Sección titulada «Cómo funciona»La sesión del panel
Sección titulada «La sesión del panel»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.
El token de sitio
Sección titulada «El token de sitio»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.
Habilidades
Sección titulada «Habilidades»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 dos compuertas
Sección titulada «Las dos compuertas»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 conmodule.token.ability:<habilidad>: la credencial tiene la habilidad. Si no, 403 conability.
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/leadsyPOST /api/trackaceptan token de sitio o clave de ingest (site_keyen el cuerpo, en la query o enX-Merez-Ingest-Key). La habilidad se comprueba al resolver la credencial (ResolvesSiteCredential). Sin ninguna,/leadsresponde 422, no 401.- El 403 de módulo y el de habilidad se distinguen por
moduleoabilityen el cuerpo.
Ejemplo
Sección titulada «Ejemplo»# 1. Login del panelcurl -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 sitiocurl -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. Usarlocurl -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"}Qué rompe
Sección titulada «Qué rompe»- 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
moduley 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 /siteen regla. Un token consitelee contacto y marca aunque el sitio no tenga módulos. Es deliberado; no le añadas un módulo.
Ver también
Sección titulada «Ver también»- Contrato: qué claves devuelve cada Resource.
- Errores: qué significa cada 401, 403 y 422.
- Versionado: qué versión de la API estás consumiendo.