Zenex CMSDocs

GET Single Post

Fetch a single post by slug, including full content.

Endpoint

Endpoint
GET /api/blogs/{blogId}/posts/{slug}

Response

Response
{
"data": {
"id": "clx1234567890",
"title": "My First Post",
"slug": "my-first-post",
"content": {
"time": 1672531200000,
"blocks": [
{
"type": "paragraph",
"data": {
"text": "This is the post content in Editor.js format."
}
}
],
"version": "2.28.0"
},
"excerpt": "A short description",
"coverImage": "https://example.com/image.jpg",
"language": "en",
"html": "<p class=\"zenex-cms__paragraph\">This is the post content in Editor.js format.</p>",
"publishedAt": "2024-01-01T00:00:00.000Z",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"categories": [...],
"tags": [...],
"metaTitle": "SEO Title",
"metaDescription": "SEO Description",
"ogImage": "https://example.com/og-image.jpg",
"ogTitle": "Social Title",
"ogDescription": "Social Description",
"canonicalUrl": "https://example.com/blog/my-first-post",
"keywords": "javascript, web",
"availableLanguages": ["en", "es"],
"translations": [
{
"language": "en",
"slug": "my-first-post",
"canonicalUrl": "https://example.com/blog/my-first-post"
},
{
"language": "es",
"slug": "mi-primer-articulo",
"canonicalUrl": null
}
]
}
}

Translations

The response includes the published translations from the same blog and translation group. Each item has its own slug and optional canonicalUrl, so clients can build language selectors and hreflang links. Posts without a translation group include only themselves. Draft and scheduled translations are excluded from both translations and availableLanguages.

Example

example.ts
const blogId = "your-blog-id";
const slug = "my-first-post";
const res = await fetch(
`https://yourdomain.com/api/blogs/${blogId}/posts/${slug}`
);
const { data: post } = await res.json();
console.log(post.title);
console.log(post.content); // Editor.js format

Content Format

The content is available in two formats:

  • content - Raw Editor.js JSON blocks structure.
  • html - Server-side rendered HTML with zenex-cms__* classes.

Rendering & Styling

The easiest way to render post content is to use the html field and include our default stylesheet.

1. Render HTML

In React / Next.js:

Post.tsx
<div
className="zenex-cms-content"
dangerouslySetInnerHTML={{ __html: post.html }}
/>

In Astro:

Post.astro
<div class="zenex-cms-content" set:html={post.html} />

2. Add Styles

Copy the following CSS to your project (e.g., zenex-cms.css) and import it.

zenex-cms.css
/* Zenex CMS Default Styles */
.zenex-cms__header {
font-weight: 700;
line-height: 1.2;
margin: 1.5rem 0 1rem;
color: inherit;
}
.zenex-cms__h1 { font-size: 2.25rem; font-weight: 800; }
.zenex-cms__h2 { font-size: 1.875rem; font-weight: 700; }
.zenex-cms__h3 { font-size: 1.5rem; font-weight: 600; }
.zenex-cms__h4 { font-size: 1.25rem; font-weight: 600; }
.zenex-cms__paragraph {
font-size: 1rem;
line-height: 1.75;
margin: 0.75rem 0;
color: inherit;
}
.zenex-cms__list {
margin: 0.75rem 0;
padding-left: 1.5rem;
}
.zenex-cms__list-item {
margin: 0.25rem 0;
line-height: 1.75;
}
.zenex-cms__list--unordered { list-style-type: disc; }
.zenex-cms__list--ordered { list-style-type: decimal; }
.zenex-cms__quote {
border-left: 4px solid currentColor;
padding-left: 1rem;
margin: 1rem 0;
font-style: italic;
opacity: 0.9;
}
.zenex-cms__code-block {
background-color: #111827;
color: #e5e7eb;
border-radius: 0.5rem;
padding: 1.25rem;
margin: 1.5rem 0;
overflow-x: auto;
border: 1px solid #374151;
}
.zenex-cms__code {
font-family: monospace;
font-size: 0.9rem;
line-height: 1.6;
color: inherit;
}
.zenex-cms__image-figure { margin: 1.5rem 0; }
.zenex-cms__image {
max-width: 100%;
height: auto;
border-radius: 0.5rem;
}
.zenex-cms__image-caption {
font-size: 0.875rem;
text-align: center;
margin-top: 0.5rem;
opacity: 0.8;
}
.zenex-cms__link-tool {
border: 1px solid currentColor;
opacity: 0.8;
border-radius: 0.5rem;
margin: 1rem 0;
padding: 1rem;
display: block;
text-decoration: none;
}