# Pluma

> A general-purpose headless CMS, docs first, made so an AI agent can run it on its own.

Every page is available as raw markdown at the URL ending in `.md`. Pages marked "pending" don't describe something built yet: don't use them as if it existed.

## Get started

- [What Pluma is](https://www.pluma.so/docs/start/what-is-pluma.md): Pluma is a headless CMS: it stores your site's content (posts, events, pages, settings) and serves it by API to any frontend. Astro, Next, Nuxt, Eleventy, a mobile app: it doesn't matter.
- [Concepts](https://www.pluma.so/docs/start/concepts.md): The names are Contentful's, on purpose: if you have used it, you already know what each thing is called.
- [First 5 minutes](https://www.pluma.so/docs/start/first-5-minutes.md): From zero to reading your first content by API. If you'd rather have your agent do it, jump to Invite your agent: it does these steps by itself.

## Guides: the 5 steps of every site

- [Step 1 · Create the site](https://www.pluma.so/docs/guides/create-a-site.md): Each site in Pluma is a space: it has its own content, team, keys and deploys. A person does this step, because creating the site sets who the owner is.
- [Step 2 · Invite your agent](https://www.pluma.so/docs/guides/invite-your-agent.md): You don't set up anything technical. You create a link, give it to your agent (Claude, ChatGPT, Claude Code, Cursor), and it does the rest: it reads your site, proposes how to model the content,…
- [Model your content](https://www.pluma.so/docs/guides/content-model.md): A content type is the shape of a piece of content: which fields it has. You define it in the dashboard, with no code.
- [Create and publish content](https://www.pluma.so/docs/guides/entries.md): An entry is a specific piece of content: the event "Open House", the post "Welcome, families". Each entry belongs to a content type and has one value per field.
- [Step 3 · Connect the MCP](https://www.pluma.so/docs/guides/connect-mcp.md): With the MCP connected, your agent manages content with tools: "publish the Open House", "show me the drafts", "upload this photo". No curl and no copying responses.
- [Images and files](https://www.pluma.so/docs/guides/files.md): An asset is a file in your site: a photo, a logo, a PDF, a short video. You upload it once and use it in any entry.
- [Step 4 · Invite your team](https://www.pluma.so/docs/guides/team.md): Add the people who write or review the content. Users are unlimited on every site.
- [Step 5 · Deploy on Netlify](https://www.pluma.so/docs/guides/deploy-netlify.md): Pluma doesn't build your site: it notifies whoever builds it. When you publish something, Pluma calls a Netlify build hook and Netlify rebuilds the site with the new content.
- [Deploy on Vercel](https://www.pluma.so/docs/guides/deploy-vercel.md): Same as Netlify, with a Vercel Deploy Hook.
- [Generic webhook deploy](https://www.pluma.so/docs/guides/deploy-webhook.md): For any other host or CI: Cloudflare Pages, GitHub Actions, your own server, a Slack channel. Pluma sends a POST with JSON when something happens, signed so you can verify it comes from Pluma.
- [Composable pages](https://www.pluma.so/docs/guides/composable-pages.md): With this, a new page on the site ("Tuition", "Our mission") gets built by chat, without touching code: your agent creates the page in Pluma with sections the site already knows how to render,…
- [Migrate from repo files](https://www.pluma.so/docs/guides/migrate-from-files.md): This guide is for your agent. It's the "match": turning the content that lives today in repo files (JSON, markdown with frontmatter, config) into Pluma content types and entries, without losing…
- [Staging and previews](https://www.pluma.so/docs/guides/staging.md): See a draft on your real site before you publish it. Works with any host: Netlify, Vercel, Cloudflare Pages, your own server.
- [Migrate from Contentful](https://www.pluma.so/docs/guides/migrate-from-contentful.md) (pending, phase 9): Exporting from Contentful and importing into Pluma, field by field.
- [Billing](https://www.pluma.so/docs/guides/billing.md) (pending, phase 6): Price, the 14-day trial, what happens if you stop paying (the Delivery API keeps serving).
- [AI visibility](https://www.pluma.so/docs/guides/ai-visibility.md): When someone asks ChatGPT, Claude or Perplexity about what you sell, the assistant reads websites first and then answers. If it can't read yours, it recommends someone else.
- [Analytics](https://www.pluma.so/docs/guides/analytics.md): See who visits your site and where they came from, including which AI assistant sent them (ChatGPT, Perplexity, Gemini, Claude, Copilot…) and which AI crawlers read which pages.
- [AI answers](https://www.pluma.so/docs/guides/ai-answers.md): What do ChatGPT and Gemini say when a customer asks for what you sell? AI answers, in Visibility, asks them every week and tells you, for each:
- [Search Console and Bing](https://www.pluma.so/docs/guides/search-console.md): See what people searched on Google and Bing before they saw your site or clicked it: the top searches and pages, with clicks, impressions, CTR and average position, for the last 28 days.
- [Site preview](https://www.pluma.so/docs/guides/site-preview.md): Each site in Sites shows a picture of its live home page, so you recognize it at a glance.

## API

- [API · conventions](https://www.pluma.so/docs/api/index.md): Everything you do in the dashboard can be done by API. This page explains what applies to every endpoint.
- [Delivery API](https://www.pluma.so/docs/api/delivery.md): Reading content. With a delivery key it returns what is published; with a preview key, the latest version (see Preview API). General conventions in API.
- [Preview API](https://www.pluma.so/docs/api/preview.md): It's the Delivery API, with a preview key. Same routes, same parameters, same response shape. The difference:
- [Management API](https://www.pluma.so/docs/api/management.md): Writing: the model, the entries, the files. It needs a management key or an agent token (pluma_agt_, see Agents); with a delivery or preview key you get key_cannot. Conventions in API.
- [Agents](https://www.pluma.so/docs/api/agents.md): An agent is a first-class user: it has a name, its own permissions and its own token. You invite it with a one-time link (see Invite your agent).
- [Webhooks](https://www.pluma.so/docs/api/webhooks.md): Deploy hooks through the API. Needs the manage_webhooks permission (agents and management keys have it). What Pluma sends and how to verify it: Generic webhook deploy.

## MCP

- [MCP](https://www.pluma.so/docs/mcp/index.md): Pluma has a remote MCP server. Your agent (Claude Code, Claude, Cursor, ChatGPT) connects to it once and then manages your content with tools, without writing curl.
- [MCP tools](https://www.pluma.so/docs/mcp/tools.md): They all work on the token's site. Arguments and responses have the same shape as the API: everything the API does, the MCP does, and the last column says which route each tool maps to.
- [MCP OAuth](https://www.pluma.so/docs/mcp/oauth.md): MCP clients (ChatGPT, Claude, Claude Code, Cursor, VS Code, Codex and others) connect with OAuth 2.1: they open a Pluma screen, you pick the site and approve, and the client is connected.

## Reference

- [Rich text](https://www.pluma.so/docs/reference/rich-text.md): In the dashboard you write in markdown. Through the API (phase 3) you send JSON or markdown.

## Errors

- [Errors](https://www.pluma.so/docs/errors/index.md): Every API error has this shape:
- [Error: check_unavailable](https://www.pluma.so/docs/errors/check_unavailable.md): HTTP 422 · The readiness check couldn't run.
- [Error: invalid_body](https://www.pluma.so/docs/errors/invalid_body.md): HTTP 400 · The request body is not valid JSON.
- [Error: invalid_key](https://www.pluma.so/docs/errors/invalid_key.md): HTTP 401 · The key does not exist or was revoked.
- [Error: invalid_parameter](https://www.pluma.so/docs/errors/invalid_parameter.md): HTTP 400 · A parameter is not valid.
- [Error: invite_expired](https://www.pluma.so/docs/errors/invite_expired.md): HTTP 410 · This invite link has expired.
- [Error: invite_used](https://www.pluma.so/docs/errors/invite_used.md): HTTP 410 · This invite link has already been used.
- [Error: key_cannot](https://www.pluma.so/docs/errors/key_cannot.md): HTTP 403 · This key cannot do that.
- [Error: missing_key](https://www.pluma.so/docs/errors/missing_key.md): HTTP 401 · The key is missing.
- [Error: not_found](https://www.pluma.so/docs/errors/not_found.md): HTTP 404 · It does not exist.
- [Error: rate_limited](https://www.pluma.so/docs/errors/rate_limited.md): HTTP 429 · Too many requests with this token.
- [Error: validation_failed](https://www.pluma.so/docs/errors/validation_failed.md): HTTP 422 · The data did not pass validation.
- [Error: version_conflict](https://www.pluma.so/docs/errors/version_conflict.md): HTTP 409 · Someone saved another version in the meantime.
- [Error: wrong_space](https://www.pluma.so/docs/errors/wrong_space.md): HTTP 403 · This key belongs to another site.

## Frameworks

- [Astro](https://www.pluma.so/docs/frameworks/astro.md): How an Astro site reads its content from Pluma without changing its pages, with the repo's files as a fallback.
- [Plain fetch](https://www.pluma.so/docs/frameworks/fetch.md): For any language or framework: the Delivery API is a GET with your key. No SDK.

## Optional

- [Everything in one file](https://www.pluma.so/llms-full.txt)
- [OpenAPI 3.1](https://www.pluma.so/openapi.json): the API contract
