Version history you can restore
Every publish, unpublish, archive, discard and restore records a version. Compare one with the current entry, then restore any published version. Restoring publishes it again.
Headless CMS · invite-only early access
StackRoom is for teams who build their own front ends. Model content without counting types or entries, fetch a whole page in one request with references already expanded, and serve files from a CDN zone that belongs to your organization.
Moving from Contentful? Import your space directly.
article /api/delivery/v1/field-notes/production/entries/ent_7Qm2… { "id": "ent_7Qm2Lx9Vb4Hc8Tn1Rw", "modelApiId": "article", "data": { "title": "Twelve hours on the night ferry", "slug": "night-ferry", "author": { "id": "ent_3Kd8Wq2Np6Ys1Fj9Lb", "modelApiId": "author", "data": { "name": "Inês Duarte", "role": "Contributing editor" }, "publishedAt": "2026-09-02T10:14:00.000Z", "version": 2 }, "hero": { "id": "ast_5Hv1Rz8Mc3Qe7Pk2Wd", "url": "https://media.fieldnotes.example/ferry-deck.jpg", "mimeType": "image/jpeg", "width": 2400, "height": 1600, "alt": "Ferry deck at dusk, rope coiled by the rail" }, "topics": [ { "id": "ent_9Tb4Rk1Vx7Lm3Qa8Hs", "modelApiId": "topic", "data": { "name": "Slow travel" } } ], "readingTime": 9, "body": "<p>The boat leaves Piraeus at nine…</p>" }, "publishedAt": "2026-10-19T07:30:00.000Z", "version": 4, "translations": { "pt-BR": { "title": "Doze horas no ferry noturno" } }}
01Content modeling
When content types are rationed, teams cram a landing page, a press release and an FAQ into one generic "page" type and sort it out in code. StackRoom has no limit on content types or entries, so every kind of content gets a type of its own.
production and staging. Each environment keeps its own models, so a schema change can wait in staging.Text
Number & date
Media
Relationships
Presets
Advanced
AI schema assistant Paid plans
Write a sentence, paste a URL or drop in a screenshot. The assistant proposes fields and groups, and only ever adds: it never edits or removes what's already there, and nothing is saved until you press Save.
name Short textRequired address Long text openingHours JSON object phone Phone photos Asset gallery Illustrative proposal.
02Delivery API
A plain REST API that returns JSON. Linked entries and assets come back inline, so a page with an author, a hero image and related posts is one call, not a chain of follow-up requests.
Read the Delivery API reference/api/delivery/v1/{project}/{environment}
/entries List, filter and sort entries /entries/{id} One entry, references expanded /models Every content model /models/{id} One model and its fields /assets List assets /assets/{id} One asset /entries/{id}/events Record an A/B view or conversion BASE=https://app.stackroom.co/api/delivery/v1 curl -G "$BASE/field-notes/production/entries" \ -H "Authorization: Bearer $STACKROOM_API_KEY" \ -d model=article \ -d "fields.title[match]=ferry" \ -d "fields.readingTime[lte]=10" \ -d order=-publishedAt -d limit=12
{ "entries": [ { "id": "ent_7Qm2Lx9Vb4Hc8Tn1Rw", "modelApiId": "article", "data": { "title": "Twelve hours on the night ferry", "author": { "data": { "name": "Inês Duarte" } … }, "readingTime": 9, … }, "version": 4 } ], "total": 1, "limit": 12, "offset": 0 }
Example request against a synthetic project. Response shortened with “…”.
fields.{apiId}[op]= with eq · ne · in · nin · lt · lte · gt · gte · match · prefix · empty · notEmpty, and
has · hasNot · hasAny · hasAll · empty · notEmpty for list fields. Sort with order=-fields.{apiId}.
Filtering guide sk_dlv_…) reads only what's published. A preview key
(sk_prv_…) also returns drafts, for preview builds. Keys can be limited to
particular projects and environments.
data is always the default locale. Localized fields add a
translations object that holds only the overrides, so every other
locale falls back to the default.
fetch or any HTTP client in any language works.
Each key can make 300 requests a minute, and errors come back as JSON with a message.
03Editing and publishing
A published entry keeps serving while someone edits it. Changes go live when they press Publish, and any earlier published version is one click from coming back.
Saved as you type. Not on the Delivery API yet.
Live for delivery keys, with a version number to cache on.
Edits wait here while the published version keeps serving.
Out of the API, kept in the space, restorable.
Every publish, unpublish, archive, discard and restore records a version. Compare one with the current entry, then restore any published version. Restoring publishes it again.
Mark a field as localized and each locale stores just its overrides. Untranslated fields fall back to the default locale instead of being copied into every language.
Invite people into the organization with one of five roles, from read-only to owner.
Each entry and asset has a References tab that maps what links to it and what it links to, so you know what a change touches before you archive anything.
04Assets and CDN
Each organization gets its own Bunny storage zone and pull zone, not a slot on a shared bucket. You pick where files are stored, which regions serve them and which domain they're served from.
https://media.fieldnotes.example/en-US/1760857800000-ferry-deck.jpg?width=960&format=auto
width, height, format (webp, avif or auto) and quality to the Delivery API and asset URLs come back resized. One main region, chosen when you set up the organization, plus optional geo-replication.
Turn on the parts of the world your audience is in.
Replace a file or edit alt text, and the change waits until you publish it. Archive an asset to take it out of the API without deleting it. Each locale can have its own file and alt text.
Storage, bandwidth and API requests are tracked per organization, with a daily bandwidth chart.
05Experiments and webhooks
A/B testing Paid plans
Override any fields for a variant, set the split, and the Delivery API returns the variants with their weights. Your front end picks an arm per visitor and posts views and conversions back. StackRoom reports the rates and uplift, and you declare the winner.
A/B testing guide| Arm | Visitors | Conversion | Uplift |
|---|---|---|---|
| Control 50% Twelve hours on the night ferry | 2,140 | 4.5% | — |
| Variant B 50%Leading The slow way to Crete | 2,095 | 5.8% | +29% |
Last 30 days. Illustrative numbers.
Webhooks
Subscribe to entry.publish, entry.draft and
entry.archive for a project, an environment and the content types you choose.
Each delivery carries the full entry, references expanded, like a Delivery API read.
POST https://build.fieldnotes.example/hooks/stackroom X-Stackroom-Secret: whsec_… { "type": "entry.publish", "project": "field-notes", "environment": "production", "entry": { "id": "ent_7Qm2…", "version": 4, … } }
If your endpoint fails, StackRoom keeps trying: 6 attempts over about 14 hours.
A webhook pauses itself after 10 failed deliveries in a row. Every delivery is logged and can be sent again.
06Migrate from Contentful
The importer reads your content types, entries, assets and locales from Contentful and recreates them in StackRoom. Rich text becomes HTML, asset files are copied to your own CDN zone, and references are linked up once every entry exists.
Paste a Contentful personal access token, from Settings → API keys → Content management tokens.
Choose the Contentful space and environment to bring across.
See how many content types, entries and assets will move, and every field that cannot map one to one.
The import runs in the background with progress, into the StackRoom environment you started it from.
No silent losses. Fields that change shape are flagged in the preview before anything is imported, for example:
07Pricing
No plan counts content types or entries. Plans differ in projects, seats, requests, storage and bandwidth, plus three features that are on paid plans only.
$0 / month
For one site or app, with its production and staging environments.
Set with you
There's no self-serve checkout during early access. We set up paid plans with each team, sized to the limits it needs.
StackRoom is invite-only during early access. Request a demo and tell us what you are building. If it is a fit, you get an invitation and set up your organization from there.
No plan, Free included, caps how many content types or entries you create. Plans limit projects, environments, team members, API keys, monthly API requests, asset storage and CDN bandwidth instead.
Not today. The Delivery API is REST over HTTPS with JSON responses and bearer-token auth, so fetch or any HTTP client works. References and assets come back expanded, which covers most of what people reach for GraphQL to do. Each key can make 300 requests a minute.
Create a preview key and use it where you build previews. It returns drafts and pending changes as well as published content, while delivery keys only ever see what is published.
Content types, entries, assets and locales. Rich text is converted to HTML and asset files are copied into your CDN zone. Fields that can’t map one to one, such as Location or untyped Object fields, are imported as JSON and flagged in the preview before you start, so you can decide first.
In a Bunny storage zone created for your organization, in the main region you choose at setup, with optional geo-replication. Files are served from your own pull zone, on a custom domain with a free TLS certificate if you add one.
There are five roles: viewer, author, editor, admin and owner. Admins and owners manage settings such as API keys, webhooks, domains and members.
Tell us what you're building and we'll walk you through StackRoom with your own content model in mind.