Getting started

From sign-up to first published entry in roughly ten minutes. The path covers four steps: sign up, install the CLI, push a schema, fetch through the SDK.

1. Sign up

Pick a preset on the pricing page. Stripe takes you to checkout; on success you land in the Studio with an empty workspace. Magic-link sign-in works out of the box; passkeys can be registered from /settings.

The default workspace ships with one space called default. The control plane provisions everything in EU (Frankfurt) unless you bought a country-specific residency module — Belgian, Luxembourgish, Swiss, etc.

2. Install the CLI

In the customer repo where your schemas will live:

pnpm add -D @estokad/cli @estokad/schema
pnpm estokad init

estokad init scaffolds:

estokad.config.ts                  # workspace, region, apiUrl, paths
schemas/index.ts                   # re-export entry point
schemas/site-settings.ts           # tiny singleton, smoke test the loop
.estokad/.gitignore

The config file:

export default {
  workspace: 'your-workspace-slug',
  apiUrl: 'https://api.estokad.com',
  region: 'eu-fra-1',
}

3. Push a schema

Issue a management API key from /settings/api-keys in the Studio. Keys are prefixed by scope — ek_m_… for management, ek_w_… write, ek_d_… read-draft, ek_r_… read. Set the management key in your shell:

export ESTOKAD_API_KEY='ek_m_…'

Then push:

pnpm estokad push

Expected output:

✓ loaded 1 definitions from ./schemas
✓ compiled to JSON IR (1 types)
✓ pushed to your-workspace@eu-fra-1 (1 types)
✓ state saved to ./.estokad/schema-state.json

The state file maps type/field names to UUIDs across runs — commit it so renames stay stable for your team.

Open the Studio: the siteSettings type now appears in the Library. Create a draft, fill in siteName, publish.

4. Fetch the entry

Install the framework-agnostic SDK or the Next.js adapter:

pnpm add @estokad/sdk
# or, for Next.js (re-exports the SDK + adds draft mode, EstokadProvider,
# auto-tagging Estokad.* components — self-contained, no extra deps):
pnpm add @estokad/next

Issue a read API key (/settings/api-keys, scope read — it looks like ek_r_…) and use it as a public client token. createClient returns a proxy where each content type is a property, so cms.<type> exposes .get(), .list(), and the write methods. Field values sit at the top level of each entry alongside id, status, and publishedAt.

import { createClient } from '@estokad/sdk'

const cms = createClient({
  workspace: 'your-workspace-slug',
  apiUrl: 'https://api.estokad.com',
  apiKey: process.env.ESTOKAD_PUBLIC_KEY, // an ek_r_… read key
})

// Singleton: one entry — read the first (and only) row.
const [settings] = await cms.siteSettings.list({ first: 1 })
console.log(settings.data.siteName) // schema fields live under `data`

In a Next.js App Router page, fetching a collection and a single entry:

import { createClient } from '@estokad/next'

const cms = createClient({
  workspace: 'your-workspace-slug',
  apiUrl: 'https://api.estokad.com',
  apiKey: process.env.ESTOKAD_PUBLIC_KEY,
})

export default async function Home() {
  const articles = await cms.article.list({ first: 20, offset: 0 })
  return (
    <ul>
      {articles.map((a) => (
        <li key={a.id}>{a.title}</li>
      ))}
    </ul>
  )
}

// A single entry by slug — returns null on 404, ready for generateStaticParams.
// const article = await cms.article.get({ slug })

@estokad/next re-exports createClient so you don't install @estokad/sdk separately. The full read reference — collections, singletons, drafts, and cache revalidation — is in Fetching content. For fully-generated types you can also point openapi-typescript at /v1/<workspace>/openapi.json.

Version support. @estokad/next targets Next ^14.2 || ^15 and React ^18.2 || ^19. The data, draft-mode, overlay-route, rich-text, and token surfaces are fully typed and run on all of those. The async visual-edit components (EstokadProvider, <Estokad.*>) run on Next 14 but only typecheck under React 19's types — on a React-18 project, deliver visual edit via the overlay route + injected script instead (the components are only a convenience wrapper around that). See the package README's Compatibility section for the details and the one-line call-site workaround.

That is the full loop. Schema in code → push → publish → fetch.

Where to go next

For deeper schema work, see defineType(). For the editor experience and live preview, see Visual edit. For locking down access, see Auth & RBAC.