Docs/Quickstart

Quickstart

This guide walks you from zero to your first published content fetched via the Delivery API. You will:

  1. Get your API credentials
  2. Create a content model
  3. Create and publish an entry with localized content
  4. Fetch published content via the Delivery API
  5. 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 .env file, 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 (like slug) 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