CMS Documentation

API Editorial (Blog CMS)

Guia tecnica completa para integrar lectura, creacion, actualizacion, cambios de estado, eliminacion y preview tokenizado del Blog CMS.

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: &lt;PUBLIC_SUPABASE_ANON_KEY&gt;"   -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
slugstringSiRegex slug: a-z0-9-.
categoryIdUUIDSiDebe existir categoria.
featuredImageobj|nullNoSi existe, url y alt son obligatorios.
authorIdUUID|nullNoSi viene string, debe ser UUID.
tagsUUID[]NoArray de UUID validos.
faqsarrayNoquestion 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
400INVALID_JSON, INVALID_SLUG, EMPTY_PATCH, MISSING_QUERY_PARAMSPayload o query invalido.Corregir body/query segun validadores.
401MISSING_AUTHORIZATION, INVALID_TOKENJWT ausente/expirado.Renovar sesion y reenviar Bearer token.
403EDITORIAL_ACCESS_DENIED, INSUFFICIENT_ROLEPerfil sin permisos.Revisar profiles.role e is_active.
409STATUS_TRANSITION_NOT_ALLOWED, STATUS_UNCHANGEDTransicion invalida o redundante.Validar estado actual antes de llamar.
429RATE_LIMIT_EXCEEDEDExceso de requests en ventana corta.Aplicar retry con backoff.