Kamaankamaan

API de blog: cómo obtener y renderizar contenido de un CMS headless en cualquier framework

Cada tutorial de CMS elige un framework. Esta guía recorre un endpoint REST de Kamaan alimentando Next.js, Nuxt, SvelteKit, Astro y React, con todo el código fetch y la forma JSON de respuesta.

Junaid Khalid
Junaid Khalid
29 de mayo de 2026 · 11 min read

API de blog: cómo obtener y renderizar contenido de un CMS headless en cualquier framework

Cada framework tiene su propio tutorial de SDK de CMS. La documentación de Next.js te muestra Contentful. La de Nuxt te muestra Sanity. La de SvelteKit te muestra Storyblok. La de Astro te muestra Strapi. Ninguna te muestra lo que realmente quieres: un endpoint, una forma JSON, cinco frontends consumiéndola sin un SDK específico de proveedor en ninguno de ellos. El resultado son equipos que eligen un CMS, quedan atados a su librería de cliente, y vuelven a migrar cada vez que cambian de framework. Una API de blog que devuelve JSON REST plano rompe ese patrón. Este artículo recorre un endpoint así, la forma que devuelve y el código fetch exacto para Next.js, Nuxt, SvelteKit, Astro y React puro.

Conclusiones rápidas

  • Una API de blog es solo un endpoint REST que devuelve artículos en JSON. No hace falta SDK.
  • El mismo endpoint puede alimentar Next.js, Nuxt, SvelteKit, Astro y React con menos de 15 líneas de fetch por framework.
  • Una respuesta limpia incluye id, title, slug, content (markdown o HTML), excerpt, featured_image_url, language y parent_article_id para traducciones.
  • Kamaan es el centro de mando para fundadores multiproducto y agencias que operan muchos blogs SaaS: gestiona todos tus blogs desde un solo panel y ejecuta cada operación desde Claude, ChatGPT, Cursor o cualquier cliente MCP.
  • El cableado inicial toma entre 40 y 60 minutos a un desarrollador. Los blogs posteriores reutilizan el mismo patrón.

Por qué una API de blog portable importa más que otro SDK

El trabajo de un CMS es almacenar contenido y devolverlo. Los SDK añaden un envoltorio a ese trabajo. Los envoltorios se sienten útiles al principio, luego se vuelven fricción. Actualizas el framework, el SDK rompe. Cambias de framework, el SDK no existe. Lanzas un segundo producto, pagas por espacio y por asiento por el SDK alrededor del cual ya escribiste código de pegamento. Una API REST plana evita todo eso. Si tu CMS devuelve JSON, tu frontend puede renderizarlo.

Este artículo usa la API REST de Kamaan como ejemplo porque devuelve una forma JSON plana y predecible y porque el mismo endpoint sirve a cada sitio de tu cuenta. El patrón funciona contra cualquier CMS que exponga REST. Si quieres una introducción a la decisión arquitectónica, el pilar sobre cómo añadir un blog a un SaaS cubre cuándo elegir headless frente a un blog dentro de la app. La pieza complementaria sobre qué es un CMS headless explica la separación entre almacenamiento y renderizado.

Así se ve el mismo fetch en los cinco frameworks de un vistazo:

Tarjeta destacada del tutorial de API de blog que muestra un único endpoint REST de Kamaan renderizado por Next.js, Nuxt, SvelteKit, Astro y React puro

El endpoint de ejemplo y la forma de respuesta

Esta es la llamada que hace cada framework de abajo:

GET https://api.kamaan.io/v1/sites/{site_id}/articles?language=en&status=published
Authorization: Bearer kmn_pk_live_xxxxxxxxxxxxxxxx

La respuesta es un arreglo JSON de artículos. Cada elemento se ve así:

{
  "id": "art_2k1nB7Vy8q",
  "title": "Blog API: How to Fetch and Render Headless CMS Content in Any Framework",
  "slug": "blog-api",
  "content": "# Blog API\n\nEvery framework has its own CMS SDK tutorial...",
  "excerpt": "One Kamaan endpoint, rendered five different ways.",
  "featured_image_url": "https://cdn.kamaan.io/img/km0013_featured.png",
  "language": "en",
  "parent_article_id": null,
  "status": "published",
  "tags": ["headless-cms", "blog-api", "developer-integration"]
}

Un artículo por slug usa:

GET https://api.kamaan.io/v1/sites/{site_id}/articles/blog-api?language=es

Las traducciones se enlazan a la fuente vía parent_article_id. Para pedir la versión alemana del mismo artículo, cambia language=en por language=de. No hay un endpoint extra de traducción. El objeto del artículo es la misma forma en todos los idiomas.

Fetch uno: Next.js App Router

Componente de servidor, corre en build o bajo demanda con control de caché:

// app/blog/page.tsx
const SITE_ID = process.env.KAMAAN_SITE_ID!;
const TOKEN = process.env.KAMAAN_TOKEN!;

async function getArticles() {
  const res = await fetch(
    `https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=es&status=published`,
    {
      headers: { Authorization: `Bearer ${TOKEN}` },
      next: { revalidate: 600 },
    },
  );
  if (!res.ok) throw new Error("Kamaan fetch failed");
  return res.json();
}

export default async function BlogIndex() {
  const articles = await getArticles();
  return (
    <ul>
      {articles.map((a: any) => (
        <li key={a.id}>
          <a href={`/blog/${a.slug}`}>{a.title}</a>
          <p>{a.excerpt}</p>
        </li>
      ))}
    </ul>
  );
}

La línea next: { revalidate: 600 } le dice a Next.js que cachee la respuesta 10 minutos. Para un blog de marketing que publica unas veces a la semana, es un buen valor por defecto. Si quieres estático puro, cambia a force-cache. Si quieres cada request fresca, cambia a no-store. Para el patrón completo con la página de detalle e ISR, ve la guía de CMS headless para Next.js.

Fetch dos: Nuxt 3

Mismo endpoint, composable useFetch, corre en el servidor durante SSR:

<!-- pages/blog/index.vue -->
<script setup lang="ts">
const config = useRuntimeConfig();
const { data: articles } = await useFetch(
  `https://api.kamaan.io/v1/sites/${config.kamaanSiteId}/articles`,
  {
    query: { language: "es", status: "published" },
    headers: { Authorization: `Bearer ${config.kamaanToken}` },
    server: true,
  },
);
</script>

<template>
  <ul>
    <li v-for="a in articles" :key="a.id">
      <NuxtLink :to="`/blog/${a.slug}`">{{ a.title }}</NuxtLink>
      <p>{{ a.excerpt }}</p>
    </li>
  </ul>
</template>

useFetch deduplica automáticamente la llamada entre render servidor e hidratación cliente. El runtime config mantiene el token fuera del bundle cliente.

Fetch tres: SvelteKit

La función load del lado servidor te da control total de los headers de caché:

// routes/blog/+page.server.ts
import { KAMAAN_SITE_ID, KAMAAN_TOKEN } from "$env/static/private";

export async function load({ fetch, setHeaders }) {
  const res = await fetch(
    `https://api.kamaan.io/v1/sites/${KAMAAN_SITE_ID}/articles?language=es&status=published`,
    { headers: { Authorization: `Bearer ${KAMAAN_TOKEN}` } },
  );
  setHeaders({ "cache-control": "public, max-age=600" });
  return { articles: await res.json() };
}
<!-- routes/blog/+page.svelte -->
<script lang="ts">
  export let data;
</script>

<ul>
  {#each data.articles as a (a.id)}
    <li>
      <a href={`/blog/${a.slug}`}>{a.title}</a>
      <p>{a.excerpt}</p>
    </li>
  {/each}
</ul>

Fetch cuatro: Astro

Astro hace fetch en tiempo de build por defecto, lo cual encaja perfecto con un blog:

---
// src/pages/blog/index.astro
const SITE_ID = import.meta.env.KAMAAN_SITE_ID;
const TOKEN = import.meta.env.KAMAAN_TOKEN;

const res = await fetch(
  `https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=es&status=published`,
  { headers: { Authorization: `Bearer ${TOKEN}` } },
);
const articles = await res.json();
---

<ul>
  {articles.map((a) => (
    <li>
      <a href={`/blog/${a.slug}`}>{a.title}</a>
      <p>{a.excerpt}</p>
    </li>
  ))}
</ul>

Si cambias Astro a modo SSR, el mismo código corre por cada request. No cambia el código.

Fetch cinco: React puro (Vite)

Fetch en cliente en una app React plana. Útil cuando el blog vive dentro de un dashboard SaaS autenticado:

// src/pages/Blog.tsx
import { useEffect, useState } from "react";

const SITE_ID = import.meta.env.VITE_KAMAAN_SITE_ID;
const TOKEN = import.meta.env.VITE_KAMAAN_TOKEN;

export function Blog() {
  const [articles, setArticles] = useState<any[]>([]);
  useEffect(() => {
    fetch(
      `https://api.kamaan.io/v1/sites/${SITE_ID}/articles?language=es&status=published`,
      { headers: { Authorization: `Bearer ${TOKEN}` } },
    )
      .then((r) => r.json())
      .then(setArticles);
  }, []);
  return (
    <ul>
      {articles.map((a) => (
        <li key={a.id}>
          <a href={`/blog/${a.slug}`}>{a.title}</a>
          <p>{a.excerpt}</p>
        </li>
      ))}
    </ul>
  );
}

Para una app React en cliente, expón un token público de solo lectura. Nunca envíes un token de escritura al navegador.

Aquí está la misma imagen como tarjeta de referencia: un endpoint arriba y la ruta de archivo donde vive el fetch de cada framework debajo.

Infografía que muestra un único endpoint REST de Kamaan consumido por Next.js, Nuxt, SvelteKit, Astro y React con la ruta de archivo de cada framework

Dos escenarios reales

Escenario uno: un fundador solo que opera tres productos SaaS. Cada producto tiene su propio sitio de marketing en un stack distinto, elegido en momentos distintos. Producto A en Next.js, producto B en Astro, producto C en un dashboard React puro. Sin una API de blog portable, el fundador mantiene tres integraciones de CMS, tres flujos de contenido y tres facturas distintas. Con una cuenta Kamaan y tres sitios bajo ella, el mismo patrón de fetch corre en los tres. Los nuevos artículos redactados en Claude aterrizan en el sitio correcto vía el servidor MCP, y cada frontend los toma en la siguiente revalidación. Tiempo total de integración en los tres: menos de tres horas.

Escenario dos: una pequeña agencia con siete blogs SaaS de clientes. La agencia no quiere enseñar siete UIs de CMS distintos a siete clientes. Operan los siete blogs desde un solo panel de Kamaan, dan a cada cliente un asiento de editor limitado a su sitio, y permiten a su equipo de contenido redactar en lote desde una sola ventana de ChatGPT. Cada sitio cliente usa el framework con el que la agencia lo construyó, consumiendo la misma forma JSON.

Dónde encaja Kamaan

Kamaan es el centro de mando para fundadores multiproducto y agencias que operan muchos blogs SaaS: gestiona todos tus blogs desde un solo panel y ejecuta cada operación desde Claude, ChatGPT, Cursor o cualquier cliente MCP. El endpoint REST que se muestra arriba es la misma forma en todos los sitios de tu cuenta. Auto-Multilingual Delivery significa que las traducciones se entregan automáticamente al publicar, devueltas por el mismo endpoint de artículos con language=de, language=fr, y así. El campo parent_article_id enlaza cada traducción con su fuente original.

El precio es de $19 al mes, plano, sitios ilimitados, sin tarifas por sitio, por espacio o por asiento. El primer mes es gratis, sin tarjeta para empezar, cancelas cuando quieras. Hay un plan de por vida para equipos que prefieren pagar una vez. Los créditos de traducción IA solo se consumen si Kamaan hace la traducción. Si pegas tus propias traducciones de Claude o ChatGPT, la subida no cuesta nada.

El lado CMS del primer publish ronda los 14 minutos desde el registro hasta el primer post en vivo. La integración del desarrollador, la parte que cubre este artículo, honestamente lleva entre 40 y 60 minutos para el primer cableado.

FAQ

¿Qué es una API de blog?

Es un endpoint HTTP que devuelve artículos como datos estructurados, normalmente JSON. Tu frontend llama al endpoint, recibe los artículos y los renderiza como quieras. El CMS se ocupa del almacenamiento, la edición y la publicación.

¿Necesito un SDK específico de proveedor?

No. La función fetch nativa de cualquier runtime JavaScript moderno alcanza. Los SDK añaden conveniencia pero también atan. Un endpoint REST que devuelve JSON plano funciona con cualquier framework.

¿La misma API de blog puede alimentar varios frontends?

Sí. Ese es el punto de headless. Puedes renderizar los mismos artículos en un sitio Next.js, una documentación en Astro y un dashboard React al mismo tiempo.

¿Cómo manejo traducciones desde una API de blog?

Busca un CMS que devuelva traducciones como objetos de artículo separados ligados a la fuente por un campo padre. Kamaan usa parent_article_id. Para pedir la versión alemana, pasa language=de en el mismo endpoint.

¿Debo cachear las respuestas?

Sí, casi siempre. El contenido de un blog de marketing no cambia a menudo. Para frameworks estáticos como Astro o Next.js con revalidate, el fetch ocurre en build o en intervalos largos. Para SSR, 5 a 10 minutos suele ser seguro.

¿Y los borradores en preview?

Pasa status=draft y añade un header de autenticación o un token de preview que carguen tus editores. La mayoría de equipos envía una ruta separada /preview/[slug] detrás de un login.

¿Cómo renderizo markdown devuelto por la API?

Elige un parser de markdown que encaje con tu runtime. Para React, react-markdown. Para Vue, vue-markdown-render. Para Svelte, svelte-markdown. Para Astro, el componente integrado.

¿En qué se diferencia de elegir Contentful o Sanity?

Contentful y Sanity también exponen endpoints REST, así que el patrón funciona contra ellos. Las diferencias están en el modelo de precios y la superficie operativa. Kamaan cobra $19 al mes planos por sitios ilimitados y te da orquestación IA vía MCP.

Relacionado en Kamaan

Empieza a construir con Kamaan

Kamaan es el centro de mando para fundadores multiproducto y agencias que operan muchos blogs SaaS: gestiona todos tus blogs desde un solo panel y ejecuta cada operación desde Claude, ChatGPT, Cursor o cualquier cliente MCP. Auto-Multilingual Delivery significa que las traducciones aparecen en cada locale automáticamente al publicar. Multi-Site Management significa una cuenta, una factura, todos los blogs que operes. La REST API Delivery que se muestra en este artículo es la misma forma en todos los sitios de tu cuenta.

El precio es de $19 al mes, plano, sitios ilimitados, sin tarifas por sitio, por espacio o por asiento. El primer mes es gratis, sin tarjeta para empezar, cancelas cuando quieras. Hay un plan de por vida si prefieres pagar una vez. Pruébalo en tu próximo blog y conserva el código fetch que ya escribiste.

Frequently asked

FAQ · 8 ITEMS
¿Qué es una API de blog?

Es un endpoint HTTP que devuelve artículos como datos estructurados, normalmente JSON. Tu frontend llama al endpoint, recibe los artículos y los renderiza como quieras. El CMS se ocupa del almacenamiento, la edición y la publicación.

¿Necesito un SDK específico de proveedor?

No. La función fetch nativa de cualquier runtime JavaScript moderno alcanza. Los SDK añaden conveniencia pero también atan. Un endpoint REST que devuelve JSON plano funciona con cualquier framework.

¿La misma API de blog puede alimentar varios frontends?

Sí. Ese es el punto de headless. Puedes renderizar los mismos artículos en un sitio Next.js, una documentación en Astro y un dashboard React al mismo tiempo.

¿Cómo manejo traducciones desde una API de blog?

Busca un CMS que devuelva traducciones como objetos de artículo separados ligados a la fuente por un campo padre. Kamaan usa `parent_article_id`. Para pedir la versión alemana, pasa `language=de` en el mismo endpoint.

¿Debo cachear las respuestas?

Sí, casi siempre. El contenido de un blog de marketing no cambia a menudo. Para frameworks estáticos como Astro o Next.js con revalidate, el fetch ocurre en build o en intervalos largos. Para SSR, 5 a 10 minutos suele ser seguro.

¿Y los borradores en preview?

Pasa `status=draft` y añade un header de autenticación o un token de preview que carguen tus editores. La mayoría de equipos envía una ruta separada `/preview/[slug]` detrás de un login.

¿Cómo renderizo markdown devuelto por la API?

Elige un parser de markdown que encaje con tu runtime. Para React, `react-markdown`. Para Vue, `vue-markdown-render`. Para Svelte, `svelte-markdown`. Para Astro, el componente integrado.

¿En qué se diferencia de elegir Contentful o Sanity?

Contentful y Sanity también exponen endpoints REST, así que el patrón funciona contra ellos. Las diferencias están en el modelo de precios y la superficie operativa. Kamaan cobra $19 al mes planos por sitios ilimitados y te da orquestación IA vía MCP.

Junaid Khalid
Written by
Junaid Khalid

Junaid Khalid is the founder of Kamaan, a headless blog CMS that auto-publishes in five languages and lets you manage every product blog from one dashboard.