Pluma
Docs index
docs/guides/content-model.md View markdown →

Model your content

A content type is the shape of a piece of content: which fields it has. You define it in the dashboard, with no code. Usually your agent does it in step 2; this guide explains what it does, so you can review it or do it by hand.

Create a content type

In your site, go to Model → New type:

Field What it is Example
Name How people see it "Event"
API ID How the API asks for it. Lowercase letters, numbers and underscores; starts with a letter event
Description Optional. Your agent reads it to know what the type is for "Events on the school calendar"
Singleton Whether it has a single entry. For site settings site_settings

The API ID can't be changed later: your site already uses it to fetch the content.

Agent guidance

Each type can carry instructions for whoever adds content, a person or your agent. You edit them on the type's page, under Agent guidance:

  • When to use it and when not to. One or two sentences. "Use Pricing for tuition and fees. Not for event lists." Up to 2000 characters.
  • What it looks like. Up to 4 previews of the site, picked from your files. They must be images.
  • Help per field. One line: format, unit or example. "In USD, no symbol: 12500".

Your agent reads them before creating anything, in describe_space in the MCP and in your site's llms.txt. Over the API they come in guidance, previews and fields[].help on each content type. They help most when there are several similar types, like the sections of a page: without guidance, the agent guesses which one to use. See Composable pages.

Page URL

Tell Pluma where each entry of the type lives on your site: /blog/{slug}, /events/{id}. With it, every entry gets View live and View on staging links, and the API returns its sys.url. See Staging and previews.

Add fields

Each field has a name, an API ID, a type, and three options:

  • Required: an entry can't be published without this field.
  • Localized: it has one value per locale. If not, the same value applies to all of them.
  • Title field: the one shown in lists. One per type.

Field types

Type API What it stores Example
Short text symbol Up to 256 characters Title
Long text text Plain text with no limit Summary
Rich text rich_text JSON blocks: paragraphs, headings, lists, images. The API also returns it as markdown and HTML Post body
Integer integer 42 Seats
Decimal number number 3.5 Price
Yes / no boolean true or false Featured
Date date Date only (2026-08-14), date and time with its time zone (2026-10-12T09:00:00-06:00) or without a zone (2026-10-12T09:00:00). Stored as is, not converted to UTC Event date
JSON json Any JSON object Extra data
Slug slug Lowercase letters, numbers and hyphens. Unique within the type open-house
Tags tags List of short texts ["families", "2026"]
Reference reference Another entry. Can be limited to certain types (even types you haven't created yet) The post author
References references Several entries Related posts
File asset An image or document Cover photo
Files assets Several Gallery
List list Rows of simple item fields, in order. See Lists Menu, opening hours, social links

Lists

For things that are rows of the same small shape: the site menu (label, url), opening hours (days, open, close), social links (network, url). Each row is edited as a row in the dashboard, with add, move up and remove, instead of raw JSON.

  • A list has 1 to 10 item fields. Each has an api_id, a name and a type: symbol (default), text, integer, number, boolean or date.
  • Up to 100 rows. Empty rows are dropped when saving. The order you see is the order you get.
  • In the dashboard, when you add a field of type List, write the item fields separated by commas: Label, URL or Days, Open, Close, Closed:boolean.
  • By API or MCP, define them with item_fields and send the value as a list of objects:
{ "api_id": "navigation", "name": "Menu", "type": "list",
  "item_fields": [ { "api_id": "label", "type": "symbol" }, { "api_id": "url", "type": "symbol" } ] }
{ "fields": { "navigation": [ { "label": "Menu", "url": "/menu" }, { "label": "Visit", "url": "/visit" } ] } }

A row with a key that isn't an item field is rejected, with the name of the field it expected. If each row needs its own page, a photo or references, use a content type of its own instead.

Rules that protect your content

  • Deleting a field doesn't delete data. The field is hidden and the data stays in each entry's previous versions.
  • Changing the type of a field that already has data is rejected, with a message that explains how to migrate: create a new field, copy the data, and hide the old one.
  • An API ID is never reused within the same type, even if the field is hidden.
  • A type with entries can't be deleted until you archive them.

Possible errors

Message What to do
"That API ID already exists in this site" Choose another one, or use the type that already exists.
"The API ID must start with a letter and contain only lowercase letters, numbers and underscores" blog_post works; Blog-Post doesn't.
"You can't change the type of a field that has data" Create a new field and hide the old one.