Quickstart
This guide walks you from zero to your first published content fetched via the Delivery API. You will:
- Get your API credentials
- Create a content model
- Create and publish an entry with localized content
- Fetch published content via the Delivery API
- Use the TypeScript SDK in your own app
Prerequisites: Node.js >= 20 and a package manager (pnpm, npm, or yarn) — only needed for SDK and framework steps. The curl steps require nothing beyond a terminal.
Time estimate: Under 15 minutes.
Step 1 — Get your API credentials
After signing up for Forme Alpha, your workspace is provisioned with:
- A Secret Key (
ce_secret_...) — for the Management API (create, update, publish) - A Read Key (
ce_read_...) — for the Delivery API (fetch published content)
Save these as environment variables:
export SECRET_KEY="ce_secret_YOUR_KEY_HERE"
export READ_KEY="ce_read_YOUR_KEY_HERE"
Tip: Store keys in a
.envfile, never hardcode them in source code.
Verify your workspace is accessible:
# Management API health check
curl -s https://management.forme.sh/health
# Delivery API health check
curl -s https://delivery.forme.sh/health
Both should return {"status":"ok"}.
Step 2 — Create a content model
A content model defines the shape of your content — like a database schema for your entries. Create a "Blog Post" model with fields for title, slug, and body:
curl -s -X POST https://management.forme.sh/management/content-models \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"apiId": "BlogPost",
"name": "Blog Post",
"type": "page",
"fields": [
{
"apiId": "title",
"name": "Title",
"type": "shortText",
"required": true,
"localized": true
},
{
"apiId": "slug",
"name": "Slug",
"type": "shortText",
"required": true,
"unique": true
},
{
"apiId": "body",
"name": "Body",
"type": "richText",
"localized": true
},
{
"apiId": "publishDate",
"name": "Publish Date",
"type": "dateTime"
}
]
}' | jq
The response includes the created model with its id. Save the content model ID — you will need it to create entries:
export CONTENT_MODEL_ID="<id from response>"
Content model types:
page(routable content like blog posts),component(reusable blocks),data(structured data like settings). See Core Concepts for details.
Step 3 — Create and publish an entry
Create a blog post entry with localized title and body (English and German):
curl -s -X POST https://management.forme.sh/management/entries \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{
\"contentModelId\": \"$CONTENT_MODEL_ID\",
\"fields\": {
\"title\": { \"en-US\": \"Hello World\", \"de-DE\": \"Hallo Welt\" },
\"slug\": \"hello-world\",
\"body\": { \"en-US\": \"# Welcome\\n\\nThis is your first Forme entry.\", \"de-DE\": \"# Willkommen\\n\\nDies ist dein erster Forme-Eintrag.\" },
\"publishDate\": \"2026-03-14T00:00:00.000Z\"
}
}" | jq
The entry is created in draft status. Save the entry ID, then publish it:
export ENTRY_ID="<id from response>"
# Publish the entry
curl -s -X POST https://management.forme.sh/management/entries/$ENTRY_ID/publish \
-H "Authorization: Bearer $SECRET_KEY" | jq
The status changes from draft to published. Published entries become available via the Delivery API.
Localized fields store content per locale as
{ "en-US": "...", "de-DE": "..." }. Non-localized fields (likeslug) store a single value. See Core Concepts for details.
Step 4 — Fetch published content via the Delivery API
The Delivery API serves published content to your frontend. Use the Read Key:
# List all published entries
curl -s https://delivery.forme.sh/delivery/entries \
-H "Authorization: Bearer $READ_KEY" | jq
# Fetch a specific entry
curl -s https://delivery.forme.sh/delivery/entries/$ENTRY_ID \
-H "Authorization: Bearer $READ_KEY" | jq
# Fetch with locale resolution (returns flat fields, not locale map)
curl -s "https://delivery.forme.sh/delivery/entries/$ENTRY_ID?locale=de-DE" \
-H "Authorization: Bearer $READ_KEY" | jq
# Filter by content model
curl -s "https://delivery.forme.sh/delivery/entries?contentModelId=$CONTENT_MODEL_ID" \
-H "Authorization: Bearer $READ_KEY" | jq
With locale resolution: When you pass ?locale=de-DE, fields are resolved to a single value for that locale (with fallback chain). Without the parameter, localized fields return the full locale map.
Step 5 — Use the TypeScript SDK
Install the SDK in your project:
pnpm add @formecms/sdk
# or: npm install @formecms/sdk
Fetch published content:
import { createClient } from "@formecms/sdk";
// Read Key → DeliveryClient (automatic detection)
const client = createClient({
baseUrl: "https://delivery.forme.sh",
apiKey: process.env.READ_KEY!,
});
// List published entries
const result = await client.entries.list({ limit: 10 });
if (result.ok) {
console.log(`Found ${result.data.total} entries:`);
for (const entry of result.data.items) {
console.log(` - ${entry.id} (published ${entry.publishedAt})`);
}
} else {
console.error(`Error ${result.status}: ${result.error.message}`);
}
The SDK auto-detects your key type: a ce_secret_ key gives you a ManagementClient, a ce_read_ key gives you a DeliveryClient. See the SDK Getting Started guide for the full API.
Step 6 — Render in a Next.js app
The Forme Showcase is a complete Next.js app that demonstrates Forme's composable content modeling. It includes 12 content models (pages, components, data), a seed script, and a one-click Vercel deploy button. See it running live at showcase.formecms.com.
Clone and run:
git clone https://github.com/formecms/showcase.git
cd showcase
cp .env.example .env.local
# Edit .env.local with your Read Key:
# FORME_DELIVERY_URL=https://delivery.forme.sh
# FORME_READ_KEY=ce_read_YOUR_KEY_HERE
pnpm install
pnpm dev
Open http://localhost:3000 to see published content rendered in a production-quality site.
Seed showcase content (optional, creates example content models and entries):
FORME_MANAGEMENT_URL=https://management.forme.sh \
FORME_SECRET_KEY=ce_secret_YOUR_KEY_HERE \
pnpm seed
Deploy to Vercel using the deploy button in the showcase README — just paste your FORME_DELIVERY_URL and FORME_READ_KEY.
What the showcase demonstrates:
- Composable pages built from reusable component content models via reference fields
- 3 model types (page, component, data) and all 9 field types
- Rich text rendering from Markdown stored in the CMS
- Image assets served through the Delivery API
- Server Components + ISR for fast, cached content delivery
Step 7 — Verify environment isolation
Environments let you branch your content. Create a staging environment and verify it has its own content scope:
# Create a staging environment
curl -s -X POST https://management.forme.sh/management/environments \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "staging", "slug": "staging"}' | jq
# List environments
curl -s https://management.forme.sh/management/environments \
-H "Authorization: Bearer $SECRET_KEY" | jq
New environments start empty — entries from the production environment are not visible in the staging environment. See Core Concepts for details on how environments work.
Next steps
- Live Showcase — see Forme in action, powered by real CMS content (source on GitHub)
- Core Concepts — understand the building blocks (content models, field types, entry lifecycle, locales, environments)
- Admin UI Guide — create content models and manage entries through the browser interface
- SDK Getting Started — full TypeScript SDK reference with copy-pasteable examples
- API Reference — authentication, pagination, error handling, and links to the interactive OpenAPI docs