Guides
Build a restaurant site
Create a complete restaurant website with menu, bookings, reviews and design tokens using the OptimoCMS SDK, MCP and REST API.
Build a complete restaurant site
In this tutorial you'll build a restaurant website step by step with:
- Menu page with categories and dishes
- Online reservations via the booking system
- Customer reviews
- Design tokens for branding
- Publishing to production
Each step shows SDK, MCP and REST examples side by side.
Prerequisites
- Node.js 18+
- An OptimoCMS API key (create one in the dashboard under Settings → API)
npm install @optimocms/sdk
Step 1 — Create a site
SDK
import { OptimoCMS } from '@optimocms/sdk';
const client = new OptimoCMS({
apiKey: process.env.OPTIMOCMS_API_KEY!,
});
const site = await client.sites.create({
name: 'Ristorante Bella Vista',
subdomain: 'bellavista',
language: 'nl',
});
console.log(`Site created: ${site.id}`);MCP (Cursor / Claude)
Create a new site named "Ristorante Bella Vista" with subdomain "bellavista" in Dutch.The MCP tool create_site is called with:
{
"name": "Ristorante Bella Vista",
"subdomain": "bellavista",
"language": "nl"
}REST
curl -X POST https://api.optimocms.com/v1/sites \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Ristorante Bella Vista",
"subdomain": "bellavista",
"language": "nl"
}'Step 2 — Install a template
Choose a restaurant template from the library and install it on your site.
SDK
const templates = await client.templates.list({ category: 'restaurant' });
const template = templates.data[0];
const result = await client.templates.install(site.id, {
templateId: template.id,
designTokens: {
colorPrimary: '#8B0000',
fontHeading: 'Playfair Display',
fontBody: 'Inter',
radiusCard: '12px',
radiusButton: '8px',
},
});
console.log(`Template installed, ${result.pagesCreated.length} pages created`);MCP
Install the restaurant template on site "bellavista" with a dark red primary color (#8B0000) and Playfair Display as heading font.REST
curl -X POST https://api.optimocms.com/v1/sites/$SITE_ID/templates/install \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_restaurant_classic",
"designTokens": {
"colorPrimary": "#8B0000",
"fontHeading": "Playfair Display",
"fontBody": "Inter",
"radiusCard": "12px",
"radiusButton": "8px"
}
}'Step 3 — Populate the menu page
Create a menu page with categories and dishes as content blocks.
SDK
const menuPage = await client.pages.create(site.id, {
title: 'Menu',
slug: 'menu',
status: 'draft',
blocks: [
{
type: 'Hero',
props: {
title: 'Our Menu',
subtitle: 'Fresh Italian dishes, prepared daily',
backgroundImage: '/images/kitchen.jpg',
},
},
{
type: 'MenuCategory',
props: {
title: "Antipasti",
items: [
{ name: 'Bruschetta al Pomodoro', price: '€9.50', description: 'Toasted bread with tomato and basil' },
{ name: 'Carpaccio di Manzo', price: '€14.00', description: 'Thinly sliced beef with rocket and parmesan' },
{ name: 'Burrata con Prosciutto', price: '€16.50', description: 'Creamy burrata with parma ham' },
],
},
},
{
type: 'MenuCategory',
props: {
title: "Primi Piatti",
items: [
{ name: 'Spaghetti Carbonara', price: '€16.00', description: 'Classic with guanciale and pecorino' },
{ name: 'Risotto ai Funghi Porcini', price: '€18.50', description: 'Creamy risotto with porcini mushrooms' },
{ name: 'Tagliatelle al Ragù', price: '€17.00', description: 'Fresh pasta with slow-cooked meat sauce' },
],
},
},
{
type: 'MenuCategory',
props: {
title: "Dolci",
items: [
{ name: 'Tiramisù della Casa', price: '€9.00', description: 'Homemade according to grandma\'s recipe' },
{ name: 'Panna Cotta', price: '€8.50', description: 'With seasonal fruit and coulis' },
],
},
},
],
});
console.log(`Menu page created: ${menuPage.id}`);MCP
Create a menu page on site "bellavista" with categories Antipasti, Primi Piatti and Dolci. Add 2-3 dishes per category with name, price and short description.REST
curl -X POST https://api.optimocms.com/v1/sites/$SITE_ID/pages \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Menu",
"slug": "menu",
"status": "draft",
"blocks": [
{
"type": "Hero",
"props": { "title": "Our Menu", "subtitle": "Fresh Italian dishes" }
},
{
"type": "MenuCategory",
"props": {
"title": "Antipasti",
"items": [
{ "name": "Bruschetta al Pomodoro", "price": "€9.50" },
{ "name": "Carpaccio di Manzo", "price": "€14.00" }
]
}
}
]
}'Step 4 — Enable reservations
Configure the booking system so guests can reserve online.
SDK
const bookingPage = await client.pages.create(site.id, {
title: 'Reservations',
slug: 'reservations',
status: 'published',
blocks: [
{
type: 'Hero',
props: { title: 'Reserve a table', subtitle: 'Choose your preferred date and time' },
},
{
type: 'BookingWidget',
props: { serviceId: 'dinner', showStaff: false, showBranch: false },
},
],
});
// Fetch available slots
const slots = await client.booking.getSlots(site.id, {
serviceId: 'dinner',
date: '2026-06-15',
});
console.log(`${slots.slots.filter(s => s.available).length} available time slots`);
// Create a test reservation
const booking = await client.booking.create(site.id, {
serviceId: 'dinner',
date: '2026-06-15',
startTime: '19:00',
customer: {
name: 'Jan de Vries',
email: 'jan@example.com',
phone: '+31612345678',
},
});
console.log(`Reservation confirmed: ${booking.id} (${booking.status})`);MCP
Enable reservations on site "bellavista". Create a reservation page with a booking widget for dinner service.REST
# Fetch slots
curl https://api.optimocms.com/v1/sites/$SITE_ID/booking/slots?serviceId=dinner&date=2026-06-15 \
-H "Authorization: Bearer $API_KEY"
# Create reservation
curl -X POST https://api.optimocms.com/v1/sites/$SITE_ID/booking \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"serviceId": "dinner",
"date": "2026-06-15",
"startTime": "19:00",
"customer": {
"name": "Jan de Vries",
"email": "jan@example.com"
}
}'Step 5 — Set design tokens
Customise the branding with design tokens — these apply across all pages.
SDK
const tokens = await client.designTokens.update(site.id, {
colorPrimary: '#8B0000',
colorBackground: '#FFF8F0',
colorSurface: '#FFFFFF',
colorText: '#1A1A1A',
colorTextMuted: '#6B7280',
fontHeading: 'Playfair Display',
fontBody: 'Inter',
radiusCard: '12px',
radiusButton: '8px',
radiusInput: '6px',
});
console.log(`Design tokens updated: ${tokens.updatedAt}`);MCP
Update the design tokens of site "bellavista": primary colour dark red #8B0000, background warm white #FFF8F0, heading font Playfair Display, body font Inter.REST
curl -X PUT https://api.optimocms.com/v1/sites/$SITE_ID/design-tokens \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"colorPrimary": "#8B0000",
"colorBackground": "#FFF8F0",
"colorSurface": "#FFFFFF",
"colorText": "#1A1A1A",
"fontHeading": "Playfair Display",
"fontBody": "Inter",
"radiusCard": "12px",
"radiusButton": "8px"
}'Step 6 — Publish
Publish the site to production so visitors can reach it.
SDK
const publishResult = await client.sites.publish(site.id);
if (publishResult.status === 'queued' || publishResult.status === 'deploying') {
console.log(`Site is being published! Deploy ID: ${publishResult.deployId}`);
console.log(`Live at: https://bellavista.optimocms.com`);
}MCP
Publish site "bellavista" to production.REST
curl -X POST https://api.optimocms.com/v1/sites/$SITE_ID/publish \
-H "Authorization: Bearer $API_KEY"Response:
{
"siteId": "site_abc123",
"status": "deploying",
"deployId": "dpl_xyz789"
}Complete script
Here's the full script combining all steps:
import { OptimoCMS } from '@optimocms/sdk';
const client = new OptimoCMS({
apiKey: process.env.OPTIMOCMS_API_KEY!,
});
async function buildRestaurantSite() {
const site = await client.sites.create({
name: 'Ristorante Bella Vista',
subdomain: 'bellavista',
language: 'nl',
});
const templates = await client.templates.list({ category: 'restaurant' });
await client.templates.install(site.id, {
templateId: templates.data[0].id,
});
await client.designTokens.update(site.id, {
colorPrimary: '#8B0000',
colorBackground: '#FFF8F0',
fontHeading: 'Playfair Display',
fontBody: 'Inter',
radiusCard: '12px',
radiusButton: '8px',
});
await client.pages.create(site.id, {
title: 'Menu',
slug: 'menu',
status: 'published',
blocks: [
{ type: 'Hero', props: { title: 'Our Menu' } },
{ type: 'MenuCategory', props: { title: 'Antipasti', items: [
{ name: 'Bruschetta', price: '€9.50' },
{ name: 'Carpaccio', price: '€14.00' },
]}},
],
});
await client.pages.create(site.id, {
title: 'Reservations',
slug: 'reservations',
status: 'published',
blocks: [
{ type: 'BookingWidget', props: { serviceId: 'dinner' } },
],
});
const result = await client.sites.publish(site.id);
console.log(`✓ Site live at https://bellavista.optimocms.com (${result.status})`);
}
buildRestaurantSite().catch(console.error);Next steps
- Design tokens — Learn more about the token system
- Manage reservations — Full booking API reference
- Automate multi-site — The same flow for 50 restaurants