Blog Categorias Tags Autores API Docs 1) Base URL y Endpoints
Las escrituras editoriales se hacen por Supabase Edge Functions.
Functions Base URL
https://<project-ref>.functions.supabase.co Auth URL (login)
POST https://<project-ref>.supabase.co/auth/v1/token?grant_type=password Metodo Path Descripcion GET /cms-catalogs Consultar catalogos de categorias, autores y tags. GET /cms-blog-post Obtener detalle de post por postId o por categorySlug+slug. GET /cms-blog-posts Listar posts con filtros (status, busqueda, paginacion). POST /cms-blog-create Crear post en draft. PATCH /cms-blog-update Actualizar campos de contenido/SEO en draft o scheduled. PATCH /cms-blog-status Transiciones de estado editorial. DELETE /cms-blog-delete Eliminar post por ID (solo admin). POST /api/cms/preview-token Generar URL de preview tokenizada para draft/scheduled.
2) Autenticacion y Headers
Todos los endpoints de escritura requieren JWT de usuario autenticado en Supabase Auth
+ perfil activo en profiles con rol editorial.
curl -X POST "https://<project-ref>.supabase.co/auth/v1/token?grant_type=password" -H "apikey: <PUBLIC_SUPABASE_ANON_KEY>" -H "Content-Type: application/json" -d '{"email":"usuario@dominio.com","password":"tu-password"}' Header Requerido Uso Authorization: Bearer <jwt> Si Valida usuario y carga profiles.role. apikey: <anon-key> Si Requerido por Supabase gateway/functions. Content-Type: application/json Si Todos los bodies son JSON. x-request-id: <uuid> Opcional Trazabilidad y correlacion en logs.
3) Envelope de Respuesta Las respuestas exitosas y de error tienen forma estable.
Exito
{
"data": { ... },
"meta": {
"requestId": "uuid",
"endpoint": "cms-blog-create"
}
} Error
{
"error": {
"code": "INVALID_SLUG",
"message": "Field 'slug' must use slug format a-z0-9-",
"details": null
}
} 4) Endpoints de lectura (catalogos y posts)
Estos endpoints permiten resolver IDs reales antes de crear/editar contenido y evitar errores como
STATUS_UNCHANGED consultando el estado actual del post.
GET /cms-catalogs
Devuelve listas de categories, authors y tags.
GET /cms-catalogs?catalog=all&includeInactive=false catalog: all | categories | authors | tags (default all). includeInactive: true | false (default false). GET /cms-blog-post
Obtiene un post completo (metadata, markdown, tags, FAQs, refs de categoria/autor).
GET /cms-blog-post?postId=<uuid>
GET /cms-blog-post?categorySlug=automatizacion&slug=mi-post Usar solo uno de los dos modos de lookup. Ideal para cargar la version actual antes de editar o cambiar estado. GET /cms-blog-posts
Lista posts con filtros y paginacion para paneles editoriales o integraciones.
GET /cms-blog-posts?status=draft&search=ia&limit=20&offset=0&sort=updated_desc status: all | draft | scheduled | published. categorySlug, authorId, search son opcionales. limit: 1..100 (default 20), offset: 0..5000 (default 0). sort: updated_desc | publish_desc | publish_asc. 5) Endpoint: POST /cms-blog-create
Crea un post en estado draft. Permite incluir tags y FAQs desde el primer write.
Rol permitido: admin, editor. Rate limit: 30 req/min por usuario. Status HTTP: 201 en exito. {
"slug": "mi-slug-seo",
"categoryId": "uuid",
"h1": "Titulo H1",
"metaDescription": "Meta description",
"canonicalUrl": "https://creamvp.com/blog/categoria/mi-slug-seo",
"shortDescription": "Texto corto para listados",
"featuredImage": {
"url": "https://cdn.com/imagen.jpg",
"alt": "Texto ALT",
"metadata": { "width": 1200, "height": 630 }
},
"authorId": "uuid",
"contentMarkdown": "# Contenido",
"schemaOverride": { "@type": "BlogPosting" },
"seo": { "title": "SEO title" },
"tags": ["uuid", "uuid"],
"faqs": [
{ "question": "Pregunta", "answer": "Respuesta", "position": 0 }
]
} Campos clave:
Campo Tipo Req. Regla slugstring Si Regex slug: a-z0-9-. categoryIdUUID Si Debe existir categoria. featuredImageobj|null No Si existe, url y alt son obligatorios. authorIdUUID|null No Si viene string, debe ser UUID. tagsUUID[] No Array de UUID validos. faqsarray No question y answer obligatorios.
6) Endpoint: PATCH /cms-blog-update
Aplica cambios de contenido/SEO sobre posts en draft o scheduled.
Rol permitido: admin, editor. Rate limit: 60 req/min por usuario. Status HTTP: 200 en exito. No permite cambiar status (usar cms-blog-status). {
"postId": "uuid",
"patch": {
"h1": "H1 actualizado",
"metaDescription": "Meta actualizada",
"slug": "nuevo-slug",
"categoryId": "uuid",
"canonicalUrl": "https://creamvp.com/blog/categoria/nuevo-slug",
"shortDescription": "Resumen corto",
"featuredImage": { "url": "https://...", "alt": "ALT" },
"authorId": "uuid",
"contentMarkdown": "## Markdown",
"schemaOverride": { "@type": "BlogPosting" },
"seo": { "title": "SEO title" }
},
"tags": ["uuid"],
"faqs": [{ "question": "Q", "answer": "A", "position": 0 }]
}
Reglas criticas:
patch debe tener al menos 1 campo editable. Si envias tags, reemplaza el set completo de tags actuales. Si envias faqs, reemplaza el set completo de FAQs actuales. Si el post esta published, responde 409 UPDATE_REQUIRES_DRAFT_OR_SCHEDULED. 7) Endpoint: PATCH /cms-blog-status Gestiona transiciones editoriales de estado.
Rate limit: 30 req/min por usuario. Status HTTP: 200 en exito. {
"postId": "uuid",
"status": "draft | scheduled | published",
"scheduledPublishAt": "2026-03-10T22:00:00.000Z",
"publishDate": "2026-02-10T10:00:00.000Z",
"changeReason": "Motivo de cambio"
} Reglas de validacion:
Si status = scheduled, scheduledPublishAt es obligatorio (ISO valido). publishDate solo se permite cuando status = published. No permite pedir el mismo estado actual (409 STATUS_UNCHANGED). Transicion Roles permitidos draft -> publishedadmin, reviewer published -> draftadmin, reviewer draft -> scheduledadmin, editor scheduled -> publishedadmin, reviewer
8) Endpoint: DELETE /cms-blog-delete Elimina un post por ID.
Rol permitido: admin. Rate limit: 10 req/min por usuario. Status HTTP: 200 en exito. {
"postId": "uuid",
"changeReason": "Motivo opcional"
} 9) Endpoint interno: POST /api/cms/preview-token
Endpoint Astro (no edge function) para generar URL de preview de posts no publicados.
Requiere JWT valido y perfil editorial activo. Solo aplica para estados draft y scheduled. TTL actual del token: 30 minutos. {
"postId": "uuid"
} {
"data": {
"postId": "uuid",
"status": "draft",
"previewUrl": "https://creamvp.com/blog/preview/uuid?pt=token",
"token": "token",
"expiresAt": "2026-03-10T23:00:00.000Z"
},
"meta": {
"generatedBy": "user-id",
"generatedRole": "admin"
}
} 10) Errores comunes y diagnostico HTTP Code Causa comun Accion 400 INVALID_JSON, INVALID_SLUG, EMPTY_PATCH, MISSING_QUERY_PARAMSPayload o query invalido. Corregir body/query segun validadores. 401 MISSING_AUTHORIZATION, INVALID_TOKENJWT ausente/expirado. Renovar sesion y reenviar Bearer token. 403 EDITORIAL_ACCESS_DENIED, INSUFFICIENT_ROLEPerfil sin permisos. Revisar profiles.role e is_active. 409 STATUS_TRANSITION_NOT_ALLOWED, STATUS_UNCHANGEDTransicion invalida o redundante. Validar estado actual antes de llamar. 429 RATE_LIMIT_EXCEEDEDExceso de requests en ventana corta. Aplicar retry con backoff.