CMS
Content nodes and blocks management
The CMS module provides a flexible content management system with nodes and blocks.
Content Nodes
Nodes are the building blocks of your content. Each node has a key identifier and contains structured content via blocks.
Create Node
POST
/v1/businesses/{businessId}/nodes SDK:
sdk.cms.createNode() Create a new content node.
const result = await sdk.cms.createNode({
key: 'getting-started-with-arky',
parentId: 'node_blog_root',
slug: {
en: 'getting-started-with-arky',
es: 'comenzando-con-arky'
},
access: 'PUBLIC',
writeAccess: 'AUTHENTICATED',
status: 'ACTIVE',
blocks: [
{
key: 'title',
type: 'LOCALIZED_TEXT',
properties: { label: { en: 'Title' } },
value: [{ en: 'Welcome to Arky', es: 'Bienvenido a Arky' }]
},
{
key: 'body',
type: 'MARKDOWN',
properties: {},
value: [{ en: 'This is the introduction paragraph...', es: 'Este es el párrafo de introducción...' }]
},
{
key: 'featured',
type: 'BOOLEAN',
properties: {},
value: [true]
}
],
emailSubject: {
en: 'Welcome to Arky!',
es: '¡Bienvenido a Arky!'
}
});Parameters
| Name | Type | Description |
|---|---|---|
key required | string | Unique node key identifier |
parentId optional | string | null | Parent node ID for hierarchy |
blocks optional | Block[] | Content blocks |
slug optional | Record<string, string> | Localized URL-friendly slugs (e.g., { en: 'my-page', es: 'mi-pagina' }) |
access optional | PUBLIC | AUTHENTICATED | PRIVATE | Read access level |
writeAccess optional | PUBLIC | AUTHENTICATED | PRIVATE | Write access level |
status optional | DRAFT | ACTIVE | ARCHIVED | Publication status |
emailSubject optional | Record<string, string> | Localized email subject (for email template nodes) |
Get Node
GET
/v1/businesses/{businessId}/nodes/{id} SDK:
sdk.cms.getNode() Retrieve a node by ID, slug, or key.
// By ID
const result = await sdk.cms.getNode({
id: 'node_xyz789'
});
// By slug (locale-aware)
const result = await sdk.cms.getNode({
slug: 'getting-started-with-arky'
});
// By key (unique lookup)
const result = await sdk.cms.getNode({
key: 'homepage'
});
// Access blocks with helper methods
const heroBlock = result.getBlock('hero');
const heroValues = result.getBlockValues('hero');
const imageUrl = result.getImage('hero-image');Parameters
| Name | Type | Description |
|---|---|---|
id optional | string | Node ID (use this OR slug OR key) |
slug optional | string | Node slug (locale-aware lookup) |
key optional | string | Node key (unique lookup) |
List Nodes
GET
/v1/businesses/{businessId}/nodes SDK:
sdk.cms.getNodes() List nodes with filtering and pagination.
const result = await sdk.cms.getNodes({
parentId: 'node_blog_root',
type: 'BLOG_POST',
key: 'featured-post',
statuses: ['PUBLISHED'],
query: 'arky',
sortField: 'createdAt',
sortDirection: 'desc',
cursor: null,
limit: 10,
includeChildren: false,
createdAtFrom: '2024-01-01',
createdAtTo: '2024-12-31'
});
result.items.forEach(node => {
console.log(node.key, node.slug);
});Parameters
| Name | Type | Description |
|---|---|---|
parentId optional | string | Filter by parent node |
type optional | string | Filter by node type |
key optional | string | Filter by key |
ids optional | string[] | Filter by specific node IDs |
statuses optional | string[] | Filter by statuses |
query optional | string | Search query in content |
sortField optional | string | Sort field (createdAt, updatedAt, etc.) |
sortDirection optional | asc | desc | Sort direction |
cursor optional | string | Pagination cursor |
limit optional | number | Items per page |
includeChildren optional | boolean | Include child nodes in response |
createdAtFrom optional | string | Filter by creation date (start) |
createdAtTo optional | string | Filter by creation date (end) |
Get Node Children
GET
/v1/businesses/{businessId}/nodes/{id}/children SDK:
sdk.cms.getNodeChildren() Get child nodes of a parent node.
const result = await sdk.cms.getNodeChildren({
id: 'node_parent123',
cursor: null,
limit: 20
});
result.items.forEach(child => {
console.log(child.key);
});
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Parent node ID |
cursor optional | string | Pagination cursor |
limit optional | number | Items per page |
Update Node
PUT
/v1/businesses/{businessId}/nodes/{id} SDK:
sdk.cms.updateNode() Update an existing node.
const result = await sdk.cms.updateNode({
id: 'node_xyz789',
key: 'updated-post-key',
parentId: 'node_new_parent',
slug: {
en: 'updated-slug',
es: 'slug-actualizado'
},
access: 'AUTHENTICATED',
writeAccess: 'PRIVATE',
status: 'PUBLISHED',
blocks: [
// Updated blocks
],
emailSubject: {
en: 'Updated Subject'
}
});Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Node ID to update |
key optional | string | Updated node key |
parentId optional | string | null | Updated parent node ID |
blocks optional | Block[] | Updated content blocks |
slug optional | Record<string, string> | Updated localized slugs |
access optional | PUBLIC | AUTHENTICATED | PRIVATE | Updated read access level |
writeAccess optional | PUBLIC | AUTHENTICATED | PRIVATE | Updated write access level |
status optional | DRAFT | ACTIVE | ARCHIVED | Updated publication status |
emailSubject optional | Record<string, string> | Updated localized email subject |
Delete Node
DELETE
/v1/businesses/{businessId}/nodes/{id} SDK:
sdk.cms.deleteNode() Delete a node.
await sdk.cms.deleteNode({
id: 'node_xyz789'
});
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Node ID to delete |
Content Blocks
Blocks are reusable content components within nodes.
Block Types
| Type | Description |
|---|---|
TEXT | Plain text - stores simple strings (names, emails, IDs, URLs) |
LOCALIZED_TEXT | Localized text - stores translations {en: "...", es: "..."} |
NUMBER | Numeric values |
BOOLEAN | Boolean values |
GEO_LOCATION | Geographic location with address, coordinates |
BLOCK | Nested blocks container |
RELATIONSHIP_ENTRY | Reference to other nodes |
RELATIONSHIP_MEDIA | Reference to media files |
MARKDOWN | Localized markdown content |
EMAIL | Email address |
PHONE | Phone number |
ADDRESS | Physical address (shipping or billing) |
Generate Blocks with AI
POST
/v1/businesses/{businessId}/nodes/blocks/generate SDK:
sdk.cms.generateBlocks() Generate content blocks using AI.
const result = await sdk.cms.generateBlocks({
prompt: 'Create a landing page for a fitness app',
blockTypes: ['HERO', 'TEXT', 'CTA'],
tone: 'professional',
length: 'medium'
});
// Use generated blocks
const blocks = result.blocks;
Get Variable Metadata
GET
/v1/businesses/{businessId}/nodes/types/{nodeType}/variables SDK:
sdk.cms.getVariableMetadata() Get available template variables for a node type.
const result = await sdk.cms.getVariableMetadata({
nodeType: 'BLOG_POST'
});
// Returns available variables like {{title}}, {{author}}
Parameters
| Name | Type | Description |
|---|---|---|
nodeType required | string | Node type to get variables for |
Complete Blog Example
// Create a blog post
const post = await sdk.cms.createNode({
key: '10-tips-for-better-code',
parentId: 'node_blog_root',
slug: {
en: '10-tips-for-better-code',
es: '10-consejos-para-mejor-codigo'
},
access: 'PUBLIC',
status: 'DRAFT',
blocks: [
{
key: 'title',
type: 'LOCALIZED_TEXT',
properties: {},
value: [{ en: '10 Tips for Better Code', es: '10 Consejos para Mejor Código' }]
},
{
key: 'subtitle',
type: 'LOCALIZED_TEXT',
properties: {},
value: [{ en: 'Improve your code quality today' }]
},
{
key: 'hero-image',
type: 'RELATIONSHIP_MEDIA',
properties: {},
value: ['media:media_hero123']
},
{
key: 'content',
type: 'MARKDOWN',
properties: {},
value: [{
en: `## Introduction
Writing clean code is essential for maintainability...
## Tip 1: Use Descriptive Names
Variable names should describe their purpose...`
}]
},
{
key: 'author-email',
type: 'EMAIL',
properties: {},
value: ['[email protected]']
}
]
});
// Publish the post
await sdk.cms.updateNode({
id: post.id,
key: post.key,
blocks: post.blocks,
slug: post.slug,
access: post.access,
writeAccess: post.writeAccess,
status: 'ACTIVE'
});
Tip
Use the key field for unique content like homepages or settings pages that should only exist once.