Pluma
Docs index
docs/api/index.md View markdown →

API · conventions

Everything you do in the dashboard can be done by API. This page explains what applies to every endpoint.

Base

https://pluma.so/api/v1

Start at the root. It tells you what it is, what your key can do and where the docs are:

GET /api/v1

curl https://pluma.so/api/v1 -H "Authorization: Bearer $PLUMA_KEY"
{
  "name": "Pluma",
  "docs": "https://pluma.so/llms.txt",
  "key": { "kind": "delivery", "space": "acton-estero", "can": ["read_published"] },
  "next": "GET /api/v1/spaces/acton-estero"
}

The machine contract (OpenAPI 3.1) is at /openapi.json: use it to generate clients or to let your agent see every endpoint with its parameters.

Authentication

Every request carries a key in the header:

Authorization: Bearer pluma_dlv_…

Keys are created in the site dashboard, under Keys. The full value is shown only once; keep it in a secrets manager. You can revoke a key in one click.

Kind Prefix What it can do What for
delivery pluma_dlv_ Read what is published Your site's build. Safe to use on the build server
preview pluma_prv_ Also read drafts Preview
management pluma_mgt_ Read everything, write, publish and change the model Scripts, migrations. Never in the browser

An invited agent has its own token (pluma_agt_) with the same permissions as management, plus creating delivery and preview keys. See Agents.

Delivery and Preview are the same API: same routes, same responses. The only thing that changes is the key: with a preview key you see the latest version of each entry; with a delivery key, the published one.

Responses

  • JSON, UTF-8, snake_case in the API's names; your content's fields use their API ID as is.
  • Every object has sys (metadata: id, type, dates, version) and fields (your content).
  • The sys dates (created_at, updated_at, published_at) are ISO 8601, UTC. Date fields in your content come back exactly as you saved them, with their time zone.
  • ids are opaque and unique across all of Pluma, not per site: don't assume they start at 1 or are consecutive.

Collections and pagination

{ "sys": { "type": "Array" }, "total": 57, "skip": 0, "limit": 100, "items": [ … ] }
  • limit: up to 1000. Default 100.
  • skip: how many to skip.
  • For the next page: skip = skip + limit while skip < total.

Locales

  • Without locale, fields come in the site's default language.
  • locale=en: in that language; if a field has no value, it falls back to the fallback language. Fields that aren't localized always come with the default language's value.
  • locale=*: every language, as { "title": { "es": "…", "en": "…" } }.
  • Filters (fields.slug=…), sorting and sys.url use the language you asked for.
  • Writing takes the same locale. See Languages.

Errors

Every error says what happened, how to fix it and links to its page:

{
  "error": {
    "code": "invalid_key",
    "message": "The key does not exist or was revoked.",
    "fix": "Check that you copied all of it (it starts with pluma_). If it was revoked, create a new one in Keys.",
    "doc_url": "https://pluma.so/docs/errors/invalid_key"
  }
}

The full list is in Errors.

Cache

  • With a delivery key: Cache-Control: public, max-age=60, s-maxage=300 and ETag. Send If-None-Match and you get 304 if nothing changed.
  • With preview or management: Cache-Control: private, no-store.

Limits

  • Per token: up to 600 requests per minute (API and MCP together). Every response has X-RateLimit-Limit and X-RateLimit-Remaining. If you go over, you get rate_limited with Retry-After in seconds.
  • Per site: 1 million API calls per month. Today they are counted; the warning and the limit arrive with billing.