Quickstart

From nothing to a published entry your site reads. Five steps.

Collections require the Pro plan.

1. Create an API key

In the dashboard, go to Settings -> Developer and create a key with the collection scopes you need:

  • collections:read - list and read collections and entries
  • collections:write - create and update collections and entries, set labels
  • collections:delete - delete collections and entries

The key (flg_...) is shown once. Export it:

export FLOGGY_API_KEY=flg_xxxxxxxxxxxxxxxxxx

2. Create a collection

Curl:

curl -X POST "https://floggy-api.pehcastro.workers.dev/api/collections" \
  -H "Authorization: Bearer $FLOGGY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "landing-pages",
    "schema": {
      "title": "Landing pages",
      "fields": [
        { "name": "slug", "type": "string" },
        { "name": "headline", "type": "string" },
        { "name": "body", "type": "richtext" }
      ],
      "indexes": { "title": "headline", "slug": "slug" }
    }
  }'

CLI:

floggy collections create landing-pages --schema ./schema.json

3. Add an entry

curl -X POST "https://floggy-api.pehcastro.workers.dev/api/collections/landing-pages/entries" \
  -H "Authorization: Bearer $FLOGGY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "slug": "black-friday",
      "headline": "40% off, this week only",
      "body": "<p>Our biggest sale of the year.</p>"
    }
  }'

The response includes the entry id, its first version, and a labels object.

That entry is a draft. labels came back {}, no production label points at it, and step 5 will not find it. Writing an entry is not publishing it. Step 4 publishes.

4. Publish

Publishing means pointing the production label at a version. Three ways, pick one.

On create. Add label to the body in step 3 and you skip this step entirely:

curl -X POST "https://floggy-api.pehcastro.workers.dev/api/collections/landing-pages/entries" \
  -H "Authorization: Bearer $FLOGGY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": { "slug": "black-friday", "headline": "40% off, this week only" },
    "label": "production"
  }'

The response comes back with "labels": { "production": { "version": 1, "meta": null } }. Over the SDK this needs @floggy/cms 0.2.1 or newer; older versions drop the field, return 201, and leave you a draft with nothing to indicate it.

With the CLI, on an existing entry, by version:

floggy collections versions landing-pages <entryId>
floggy collections promote landing-pages <entryId> 1

Over REST, set the label directly:

curl -X PUT "https://floggy-api.pehcastro.workers.dev/api/collections/landing-pages/entries/<entryId>/labels/production" \
  -H "Authorization: Bearer $FLOGGY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "version": "<version>" }'

Editing later works the same way. A PATCH writes a new version but leaves production on the old one, so an edit is invisible until you move the label again.

5. Fetch from your site

Read the published entry with the SDK. No writes, so a read-only key (or none, for public collections) is enough.

// app/[slug]/page.tsx
import { createClient } from "@floggy/cms";

const floggy = createClient({
  project: "projecta",
  key: process.env.FLOGGY_API_KEY,
});

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  // Default GET serves the `production` label.
  const { entries } = await floggy.collections.entries.list("landing-pages", {
    slug,
  });
  const page = entries[0];
  if (!page) return null;

  return (
    <main>
      <h1>{page.data.headline}</h1>
      <div dangerouslySetInnerHTML={{ __html: page.data.body }} />
    </main>
  );
}

If entries comes back empty, the entry is still a draft. Go back to step 4.

That is the loop: write structured content, point production at it, read it back on your site. Write and publish are two operations, whether you do them in one call or two.

Next