Page Management API - Quick Start Guide
Overview
This guide demonstrates how to use the Page Management API to build a dynamic, SEO-optimized website where the API is the source of truth for all page content.
Quick Start
1. Create Your First Page (Admin)
POST /page/new
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"module_id": "60a7b8c9d0e1f2a3b4c5d6e7",
"slug": "about-us",
"path": "/about-us",
"title": "About Us - Our Story",
"pageType": "standard",
"active": true,
"indexed": true,
"translation": {
"lang": "en"
},
"content": "<h1>About Us</h1><p>We are a leading company...</p>",
"description": "Learn more about our company history and values",
"seo": {
"metaTitle": "About Us | Our Company Story",
"metaDescription": "Discover our journey, values, and the team behind our success. Founded in 2020, we've grown to become industry leaders.",
"ogTitle": "About Us - Our Company Story",
"ogDescription": "Discover our journey and values",
"ogImage": "https://yoursite.com/images/about-og.jpg",
"ogType": "website",
"robots": "index,follow"
},
"sitemap": {
"include": true,
"priority": 0.8,
"changefreq": "monthly"
}
}
Response:
{
"_id": "60a7b8c9d0e1f2a3b4c5d6e8",
"slug": "about-us",
"path": "/about-us",
"title": "About Us - Our Story",
"active": true,
"publishedAt": "2025-12-22T10:00:00.000Z",
"createdAt": "2025-12-22T10:00:00.000Z",
"updatedAt": "2025-12-22T10:00:00.000Z"
}
2. Fetch Page for Frontend Rendering
GET /page/path/about-us?module_id=60a7b8c9d0e1f2a3b4c5d6e7
Response:
{
"_id": "60a7b8c9d0e1f2a3b4c5d6e8",
"module_id": "60a7b8c9d0e1f2a3b4c5d6e7",
"slug": "about-us",
"path": "/about-us",
"title": "About Us - Our Story",
"pageType": "standard",
"active": true,
"indexed": true,
"content": "<h1>About Us</h1><p>We are a leading company...</p>",
"description": "Learn more about our company history and values",
"seo": {
"metaTitle": "About Us | Our Company Story",
"metaDescription": "Discover our journey, values, and the team behind our success...",
"ogTitle": "About Us - Our Company Story",
"ogImage": "https://yoursite.com/images/about-og.jpg",
"robots": "index,follow"
},
"sitemap": {
"include": true,
"priority": 0.8,
"changefreq": "monthly"
},
"viewCount": 0,
"publishedAt": "2025-12-22T10:00:00.000Z"
}
3. Create a Redirect (When Changing URLs)
POST /redirect/new
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"module_id": "60a7b8c9d0e1f2a3b4c5d6e7",
"sourcePath": "/old-about-page",
"targetPath": "/about-us",
"statusCode": 301,
"matchType": "exact",
"active": true,
"reason": "URL structure update for better SEO"
}
4. Handle 404 with Redirect Resolution (Frontend)
GET /redirect/resolve/old-about-page?module_id=60a7b8c9d0e1f2a3b4c5d6e7
Response:
{
"sourcePath": "/old-about-page",
"targetPath": "/about-us",
"statusCode": 301,
"redirectType": "permanent"
}
Frontend Integration Examples
Next.js App Router (React)
// app/[...path]/page.tsx
import { notFound, redirect } from 'next/navigation';
const API_URL = process.env.API_URL;
const MODULE_ID = process.env.MODULE_ID;
async function getPage(path: string) {
// Try to fetch page
const pageResponse = await fetch(
`${API_URL}/page/path${path}?module_id=${MODULE_ID}`,
{ cache: 'no-store' }
);
if (pageResponse.ok) {
return { type: 'page', data: await pageResponse.json() };
}
// Check for redirect
const redirectResponse = await fetch(
`${API_URL}/redirect/resolve${path}?module_id=${MODULE_ID}`
);
if (redirectResponse.ok) {
const redirectData = await redirectResponse.json();
return { type: 'redirect', data: redirectData };
}
return { type: 'not-found' };
}
export default async function Page({ params }: { params: { path: string[] } }) {
const path = '/' + (params.path?.join('/') || '');
const result = await getPage(path);
if (result.type === 'redirect') {
redirect(result.data.targetPath);
}
if (result.type === 'not-found') {
notFound();
}
const page = result.data;
return (
<div>
<h1>{page.title}</h1>
<div dangerouslySetInnerHTML={{ __html: page.content }} />
</div>
);
}
// SEO Metadata
export async function generateMetadata({ params }: { params: { path: string[] } }) {
const path = '/' + (params.path?.join('/') || '');
const response = await fetch(
`${API_URL}/page/seo${path}?module_id=${MODULE_ID}`
);
if (!response.ok) return {};
const page = await response.json();
return {
title: page.seo.metaTitle || page.title,
description: page.seo.metaDescription,
keywords: page.seo.metaKeywords,
robots: page.seo.robots,
openGraph: {
title: page.seo.ogTitle || page.title,
description: page.seo.ogDescription,
images: page.seo.ogImage ? [page.seo.ogImage] : [],
type: page.seo.ogType || 'website',
},
twitter: {
card: page.seo.twitterCard || 'summary',
title: page.seo.twitterTitle || page.title,
description: page.seo.twitterDescription,
images: page.seo.twitterImage ? [page.seo.twitterImage] : [],
site: page.seo.twitterSite,
creator: page.seo.twitterCreator,
},
alternates: {
canonical: page.seo.canonicalUrl,
languages: page.seo.alternateUrls?.reduce((acc: any, alt: any) => {
acc[alt.lang] = alt.url;
return acc;
}, {}),
},
};
}
Vue.js 3 + Nuxt (Composition API)
<!-- pages/[...path].vue -->
<script setup lang="ts">
const route = useRoute();
const config = useRuntimeConfig();
const path = computed(() => '/' + (route.params.path as string[] || []).join('/'));
const { data: page, error } = await useFetch(
`${config.public.apiUrl}/page/path${path.value}`,
{
params: { module_id: config.public.moduleId },
}
);
if (error.value) {
// Try redirect
const { data: redirectData } = await useFetch(
`${config.public.apiUrl}/redirect/resolve${path.value}`,
{
params: { module_id: config.public.moduleId },
}
);
if (redirectData.value) {
navigateTo(redirectData.value.targetPath, {
redirectCode: redirectData.value.statusCode,
});
} else {
throw createError({ statusCode: 404, statusMessage: 'Page not found' });
}
}
// SEO Head
useHead({
title: page.value?.seo.metaTitle || page.value?.title,
meta: [
{ name: 'description', content: page.value?.seo.metaDescription },
{ name: 'keywords', content: page.value?.seo.metaKeywords?.join(', ') },
{ name: 'robots', content: page.value?.seo.robots },
{ property: 'og:title', content: page.value?.seo.ogTitle },
{ property: 'og:description', content: page.value?.seo.ogDescription },
{ property: 'og:image', content: page.value?.seo.ogImage },
{ name: 'twitter:card', content: page.value?.seo.twitterCard },
],
link: [
{ rel: 'canonical', href: page.value?.seo.canonicalUrl },
],
});
</script>
<template>
<div v-if="page">
<h1>{{ page.title }}</h1>
<div v-html="page.content"></div>
</div>
</template>
Express.js Backend (Server-Side Rendering)
import express from 'express';
import axios from 'axios';
const app = express();
app.get('*', async (req, res) => {
const path = req.path;
const moduleId = process.env.MODULE_ID;
const apiUrl = process.env.API_URL;
try {
// Try to fetch page
const pageResponse = await axios.get(
`${apiUrl}/page/path${path}`,
{ params: { module_id: moduleId } }
);
const page = pageResponse.data;
// Render HTML with SEO
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${page.seo.metaTitle || page.title}</title>
<meta name="description" content="${page.seo.metaDescription}">
<meta name="robots" content="${page.seo.robots}">
<link rel="canonical" href="${page.seo.canonicalUrl}">
<!-- OpenGraph -->
<meta property="og:title" content="${page.seo.ogTitle || page.title}">
<meta property="og:description" content="${page.seo.ogDescription}">
<meta property="og:image" content="${page.seo.ogImage}">
<meta property="og:type" content="${page.seo.ogType}">
<!-- Twitter -->
<meta name="twitter:card" content="${page.seo.twitterCard}">
<meta name="twitter:title" content="${page.seo.twitterTitle || page.title}">
<meta name="twitter:description" content="${page.seo.twitterDescription}">
<meta name="twitter:image" content="${page.seo.twitterImage}">
</head>
<body>
<h1>${page.title}</h1>
${page.content}
</body>
</html>
`;
res.send(html);
} catch (error: any) {
// Try redirect
try {
const redirectResponse = await axios.get(
`${apiUrl}/redirect/resolve${path}`,
{ params: { module_id: moduleId } }
);
const redirectData = redirectResponse.data;
res.redirect(redirectData.statusCode, redirectData.targetPath);
} catch {
res.status(404).send('Page not found');
}
}
});
app.listen(3000);
Common Use Cases
1. Homepage
{
"slug": "home",
"path": "/",
"title": "Welcome to Our Website",
"pageType": "homepage",
"seo": {
"metaTitle": "Website Name | Industry Leader",
"metaDescription": "Your trusted partner for...",
"structuredData": {
"@context": "https://schema.org",
"@type": "Organization",
"name": "Your Company",
"url": "https://yoursite.com",
"logo": "https://yoursite.com/logo.png"
}
},
"sitemap": {
"include": true,
"priority": 1.0,
"changefreq": "daily"
}
}
2. Blog Article with Author
{
"slug": "how-to-improve-seo",
"path": "/blog/how-to-improve-seo",
"title": "How to Improve SEO in 2025",
"pageType": "article",
"seo": {
"metaTitle": "How to Improve SEO in 2025 | Complete Guide",
"metaDescription": "Learn proven SEO strategies for 2025...",
"ogType": "article",
"structuredData": {
"@context": "https://schema.org",
"@type": "Article",
"headline": "How to Improve SEO in 2025",
"author": {
"@type": "Person",
"name": "John Doe"
},
"datePublished": "2025-12-22",
"dateModified": "2025-12-22",
"image": "https://yoursite.com/blog/seo-2025.jpg"
}
}
}
3. Product Page
{
"slug": "premium-headphones",
"path": "/products/premium-headphones",
"title": "Premium Wireless Headphones",
"pageType": "standard",
"seo": {
"metaTitle": "Premium Wireless Headphones | Buy Now",
"metaDescription": "High-quality wireless headphones with noise cancellation...",
"structuredData": {
"@context": "https://schema.org",
"@type": "Product",
"name": "Premium Wireless Headphones",
"description": "High-quality wireless headphones...",
"image": "https://yoursite.com/products/headphones.jpg",
"offers": {
"@type": "Offer",
"price": "299.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "127"
}
}
}
}
4. Landing Page with Scheduled Publishing
{
"slug": "black-friday-2025",
"path": "/promotions/black-friday-2025",
"title": "Black Friday Sale 2025",
"pageType": "landing",
"active": true,
"indexed": true,
"scheduledAt": "2025-11-29T00:00:00.000Z",
"expiresAt": "2025-12-01T23:59:59.000Z",
"seo": {
"metaTitle": "Black Friday Sale 2025 | Up to 70% Off",
"metaDescription": "Don't miss our biggest sale of the year!",
"robots": "noindex,follow"
}
}
5. Multi-Language Pages
// English version
{
"slug": "about-us",
"path": "/en/about-us",
"title": "About Us",
"translation": {
"lang": "en",
"ref_item": null
},
"seo": {
"canonicalUrl": "https://yoursite.com/en/about-us",
"alternateUrls": [
{ "lang": "fr", "url": "https://yoursite.com/fr/a-propos" },
{ "lang": "es", "url": "https://yoursite.com/es/acerca-de" }
]
}
}
// French version
{
"slug": "a-propos",
"path": "/fr/a-propos",
"title": "À Propos",
"translation": {
"lang": "fr",
"ref_item": "60a7b8c9d0e1f2a3b4c5d6e8"
},
"seo": {
"canonicalUrl": "https://yoursite.com/fr/a-propos",
"alternateUrls": [
{ "lang": "en", "url": "https://yoursite.com/en/about-us" },
{ "lang": "es", "url": "https://yoursite.com/es/acerca-de" }
]
}
}
Sitemap Generation
// Generate sitemap.xml
async function generateSitemap() {
const response = await fetch(
`${API_URL}/page/sitemap?module_id=${MODULE_ID}`
);
const { items } = await response.json();
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${items.map((page: any) => `
<url>
<loc>${WEBSITE_URL}${page.path}</loc>
<lastmod>${new Date(page.updatedAt).toISOString()}</lastmod>
<changefreq>${page.sitemap.changefreq}</changefreq>
<priority>${page.sitemap.priority}</priority>
</url>
`).join('')}
</urlset>`;
}
// Next.js route: app/sitemap.xml/route.ts
export async function GET() {
const sitemap = await generateSitemap();
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'public, max-age=3600',
},
});
}
Testing
Test Page Creation
curl -X POST http://localhost:3000/api/page/new \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"module_id": "60a7b8c9d0e1f2a3b4c5d6e7",
"slug": "test-page",
"path": "/test-page",
"title": "Test Page",
"active": true,
"indexed": true,
"translation": { "lang": "en" }
}'
Test Page Retrieval
curl http://localhost:3000/api/page/path/test-page?module_id=60a7b8c9d0e1f2a3b4c5d6e7
Test Redirect Creation
curl -X POST http://localhost:3000/api/redirect/new \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"module_id": "60a7b8c9d0e1f2a3b4c5d6e7",
"sourcePath": "/old-test-page",
"targetPath": "/test-page",
"statusCode": 301,
"matchType": "exact",
"active": true
}'
Test Redirect Resolution
curl http://localhost:3000/api/redirect/resolve/old-test-page?module_id=60a7b8c9d0e1f2a3b4c5d6e7
Performance Tips
- Cache Published Pages: Frontend can cache pages for 1 hour
- Use CDN: Serve static content via CDN
- Lazy Load Images: Use lazy loading for page images
- Preload Critical Pages: Preload homepage and key pages
- Database Indexes: All critical indexes are already configured
Security Best Practices
- Protect Admin Endpoints: All write operations require authentication
- Sanitize HTML: Sanitize user-generated HTML content
- Rate Limiting: Implement rate limiting on public endpoints
- CORS Configuration: Configure CORS for your domain only
- Input Validation: All inputs are validated server-side
Troubleshooting
Page Returns 404
- Check
activestatus istrue - Verify
pathmatches exactly (case-insensitive) - Check
scheduledAtandexpiresAtdates - Ensure
module_idis correct
Redirect Not Working
- Verify redirect is
active - Check
matchTypematches your use case - Ensure no redirect loops exist
- Check expiration date
SEO Meta Tags Not Showing
- Verify
seoobject is populated - Check frontend meta tag rendering
- Use browser dev tools to inspect HTML
- Validate structured data with Google's Rich Results Test
Need Help?
- Review full documentation in
PAGE_MANAGEMENT_SYSTEM.md - Check API errors in response body
- Monitor server logs for detailed errors
- Test endpoints with Postman or Insomnia