A small CMS, growing thoughtfully.Download RenewCMS
Documentation

Integration reference

Browse RenewCMS API routes, request fields, access requirements and examples.

v3.7.2-beta (opens in a new tab)For your installed version, open Integration in your backoffice or read its /openapi.json.

Examples use cms.example.com. Replace it with your instance URL and keep your API keys on your server.

Search by method, path, parameter or keyword.

85 routes

Browse route groups

Articles

Read, write and publish articles. Titles can't be changed after creation.

GET/v1/article/

List one page of articles, newest update first, with the total and the tab counts (all, online, draft and suggestions). Anonymous callers get online articles only.

Access · Public · 200

Query parameters

format string · Optional
markdown, html or json. Default markdown.
page number · Optional
A whole number from 1. Default 1.
size number · Optional
5, 25, 50 or 100. Default 25.
q string · Optional
Up to 200 characters, matched anywhere in the title, ignoring case and accents.
status string · Optional
online or draft. Default both.
sort string · Optional
field:direction, with field title, status, created_at or updated_at and direction asc or desc. Default updated_at:desc.
site string · Optional
The key of a site. Only its articles are listed. An unknown key answers an empty page.
seo string · Optional
ready, suggestions or hidden. Only the articles with that SEO status are listed, before paging; counts stay unfiltered. Any other value is refused.

Request example

Bash
curl "https://cms.example.com/v1/article/"

Example response

JSON
{
  "items": [
    {
      "id": 12,
      "title": "How we price a bathroom renovation",
      "body": "A bathroom renovation is priced by room size, plumbing changes and finish level.",
      "body_format": "markdown",
      "is_online": true,
      "site_id": 1,
      "slug": "how-we-price-a-bathroom-renovation",
      "excerpt": "What drives the price of a bathroom renovation.",
      "created_at": "2026-03-12T09:14:00Z",
      "updated_at": "2026-09-10T07:00:00Z",
      "seo_status": "suggestions",
      "seo_suggestions": 2
    },
    {
      "id": 13,
      "title": "Choosing tiles for a small bathroom",
      "body": "Small rooms show every grout line.",
      "body_format": "markdown",
      "is_online": false,
      "site_id": 1,
      "slug": "choosing-tiles-for-a-small-bathroom",
      "excerpt": "",
      "created_at": "2026-03-12T09:14:00Z",
      "updated_at": "2026-09-09T07:00:00Z",
      "seo_status": "suggestions",
      "seo_suggestions": 2
    }
  ],
  "total": 30,
  "page": 1,
  "size": 25,
  "counts": {
    "all": 30,
    "online": 28,
    "draft": 2,
    "suggestions": 3
  }
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
Link to this route
GET/v1/article/{id}

Get one article. Drafts answer 404 to anonymous callers.

Access · Public · 200

Query parameters

format string · Optional
markdown, html or json. Default markdown.

The example uses resource ID 12.

Request example

Bash
curl "https://cms.example.com/v1/article/12"

Example response

JSON
{
  "id": 12,
  "title": "How we price a bathroom renovation",
  "body": "A bathroom renovation is priced by room size, plumbing changes and finish level.",
  "body_format": "markdown",
  "is_online": true,
  "site_id": 1,
  "slug": "how-we-price-a-bathroom-renovation",
  "excerpt": "What drives the price of a bathroom renovation.",
  "seo_title": "",
  "seo_description": "",
  "cover_image_id": 4,
  "cover_image_alt": "A tiled bathroom wall",
  "social_title": "",
  "social_description": "",
  "social_image_id": null,
  "canonical_url": "",
  "noindex": false,
  "seo_dismissed": [],
  "created_at": "2026-03-12T09:14:00Z",
  "updated_at": "2026-09-10T07:00:00Z"
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 404 Article not found
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
Link to this route
POST/v1/article/

Create a draft article.

Access · Verified user · 201

Query parameters

format string · Optional
markdown, html or json. Default markdown.

Request body

title string · Required
3 to 200 characters. Can't be changed later.
body string · Required
Up to 10 000 characters.

Request example

Bash
curl -X POST "https://cms.example.com/v1/article/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"title":"Choosing tiles for a small bathroom","body":"Small rooms show every grout line."}'

Example response

JSON
{
  "id": 13,
  "title": "Choosing tiles for a small bathroom",
  "body": "Small rooms show every grout line.",
  "body_format": "markdown",
  "is_online": false,
  "site_id": 1,
  "slug": "how-we-price-a-bathroom-renovation",
  "excerpt": "What drives the price of a bathroom renovation.",
  "seo_title": "",
  "seo_description": "",
  "cover_image_id": 4,
  "cover_image_alt": "A tiled bathroom wall",
  "social_title": "",
  "social_description": "",
  "social_image_id": null,
  "canonical_url": "",
  "noindex": false,
  "seo_dismissed": [],
  "created_at": "2026-03-12T09:14:00Z",
  "updated_at": "2026-09-10T07:00:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 Article title must be between 3 and 200 characters.
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
PATCH/v1/article/{id}

Update the body of an article, move it to another site, or edit its SEO fields. Send at least one field; absent fields are untouched.

Access · Verified user · 200

Query parameters

format string · Optional
markdown, html or json. Default markdown.

Request body

body string · Optional
Up to 10 000 characters. An empty string empties the body; null is refused.
site_id number · Optional
The id of an existing site, 1 or more. null is refused.
slug string · Optional
Lowercase letters, digits and single dashes, 1 to 100 characters, unique on the site. An empty string regenerates it from the title. null is refused.
excerpt string · Optional
Up to 300 characters. An empty string clears it; null is refused.
seo_title string · Optional
Up to 120 characters. An empty string clears it; null is refused.
seo_description string · Optional
Up to 320 characters. An empty string clears it; null is refused.
cover_image_id number | null · Optional
The id of an existing image, 1 or more. null removes the cover.
cover_image_alt string · Optional
Up to 200 characters. An empty string clears it; null is refused.
social_title string · Optional
Up to 120 characters. An empty string clears it; null is refused.
social_description string · Optional
Up to 320 characters. An empty string clears it; null is refused.
social_image_id number | null · Optional
The id of an existing image, 1 or more. null removes the social image.
canonical_url string · Optional
An absolute https address with a host, up to 2048 characters. An empty string clears it; null is refused.
noindex boolean · Optional
Only a flag: the article stays online. null is refused.
seo_dismissed string[] · Optional
Dismissed suggestion codes: title_long, title_empty, desc_short, desc_long, cover_alt, cover_none, slug_long, no_au, no_h, body_alt, short. Duplicates are collapsed; null is refused.

The example uses resource ID 12.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/article/12" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"body":"Updated text.","site_id":2,"slug":"bathroom-pricing","excerpt":"What drives the price.","cover_image_id":4}'

Example response

JSON
{
  "id": 12,
  "title": "How we price a bathroom renovation",
  "body": "Updated text.",
  "body_format": "markdown",
  "is_online": false,
  "site_id": 1,
  "slug": "how-we-price-a-bathroom-renovation",
  "excerpt": "What drives the price of a bathroom renovation.",
  "seo_title": "",
  "seo_description": "",
  "cover_image_id": 4,
  "cover_image_alt": "A tiled bathroom wall",
  "social_title": "",
  "social_description": "",
  "social_image_id": null,
  "canonical_url": "",
  "noindex": false,
  "seo_dismissed": [],
  "created_at": "2026-03-12T09:14:00Z",
  "updated_at": "2026-09-10T07:00:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 invalid_slug
  • 400 image_not_found
  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 404 Article not found
  • 404 site_not_found
  • 409 slug_taken (the X-Slug-Suggestion header holds the first free slug)
  • 422 invalid_url
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
PATCH/v1/article/{id}/publish

Publish an article.

Access · Verified user · 200

Query parameters

format string · Optional
markdown, html or json. Default markdown.

The example uses resource ID 12.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/article/12/publish" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 12,
  "title": "How we price a bathroom renovation",
  "body": "A bathroom renovation is priced by room size, plumbing changes and finish level.",
  "body_format": "markdown",
  "is_online": true,
  "site_id": 1,
  "slug": "how-we-price-a-bathroom-renovation",
  "excerpt": "What drives the price of a bathroom renovation.",
  "seo_title": "",
  "seo_description": "",
  "cover_image_id": 4,
  "cover_image_alt": "A tiled bathroom wall",
  "social_title": "",
  "social_description": "",
  "social_image_id": null,
  "canonical_url": "",
  "noindex": false,
  "seo_dismissed": [],
  "created_at": "2026-03-12T09:14:00Z",
  "updated_at": "2026-09-10T07:00:00Z"
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 404 Article not found
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
PATCH/v1/article/{id}/unpublish

Unpublish an article.

Access · Verified user · 200

Query parameters

format string · Optional
markdown, html or json. Default markdown.

The example uses resource ID 12.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/article/12/unpublish" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 12,
  "title": "How we price a bathroom renovation",
  "body": "A bathroom renovation is priced by room size, plumbing changes and finish level.",
  "body_format": "markdown",
  "is_online": false,
  "site_id": 1,
  "slug": "how-we-price-a-bathroom-renovation",
  "excerpt": "What drives the price of a bathroom renovation.",
  "seo_title": "",
  "seo_description": "",
  "cover_image_id": 4,
  "cover_image_alt": "A tiled bathroom wall",
  "social_title": "",
  "social_description": "",
  "social_image_id": null,
  "canonical_url": "",
  "noindex": false,
  "seo_dismissed": [],
  "created_at": "2026-03-12T09:14:00Z",
  "updated_at": "2026-09-10T07:00:00Z"
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 404 Article not found
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
DELETE/v1/article/{id}

Delete an article.

Access · Verified user · 204

Query parameters

format string · Optional
markdown, html or json. Default markdown.

The example uses resource ID 12.

Request example

Bash
curl -X DELETE "https://cms.example.com/v1/article/12" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

Plain text
204 No Content

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 404 Article not found
  • 400 The format must be one of: markdown, html, json.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
POST/v1/article/{id}/seo/check

Check the SEO of an article without saving anything. Send {} for the saved state, or fields that replace the saved values for this check only.

Access · Verified user · 200

Request body

body string · Optional
Replaces the saved body for this check only. null is refused.
slug string · Optional
Same rules as PATCH. An empty string regenerates it from the title. null is refused.
excerpt string · Optional
Up to 300 characters. null is refused.
seo_title string · Optional
Up to 120 characters. null is refused.
seo_description string · Optional
Up to 320 characters. null is refused.
cover_image_id number | null · Optional
The id of an existing image. null means no cover.
cover_image_alt string · Optional
Up to 200 characters. null is refused.
social_title string · Optional
Up to 120 characters. null is refused.
social_description string · Optional
Up to 320 characters. null is refused.
social_image_id number | null · Optional
The id of an existing image. null means no social image.
canonical_url string · Optional
An absolute https address with a host, up to 2048 characters. null is refused.
noindex boolean · Optional
null is refused.
seo_dismissed string[] · Optional
Dismissed suggestion codes, replacing the saved list for this check only. null is refused.

The example uses resource ID 12.

Request example

Bash
curl -X POST "https://cms.example.com/v1/article/12/seo/check" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"seo_title":"Bathroom costs, explained","noindex":false}'

Example response

JSON
{
  "status": "suggestions",
  "suggestions": [
    {
      "code": "desc_short",
      "field": "seo_description",
      "params": {
        "length": 49,
        "min": 70
      }
    },
    {
      "code": "no_au",
      "field": "author_ids",
      "params": {}
    }
  ],
  "slug": {
    "available": false,
    "suggestion": "how-we-price-a-bathroom-renovation-2"
  }
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 invalid_slug
  • 400 image_not_found
  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Article not found
  • 422 invalid_url
  • 403 You must verify your account to access this resource.
Link to this route

Search and sharing

RenewCMS doesn't render pages or add meta tags. These endpoints give your frontend the resolved SEO data and the list of published URLs.

GET/v1/article/{id}/seo

Get the resolved SEO object of an article: title with the site template applied, description, canonical_url, robots, og, twitter, image, authors, published_at, modified_at, fallbacks and json_ld. Drafts answer 404 to anonymous callers.

Access · Public · 200

The example uses resource ID 12.

Request example

Bash
curl "https://cms.example.com/v1/article/12/seo"

Example response

JSON
{
  "title": "How we price a bathroom renovation | Renew",
  "description": "What drives the price of a bathroom renovation.",
  "canonical_url": "https://blog.renew.example/how-we-price-a-bathroom-renovation",
  "robots": "index, follow",
  "og": {
    "type": "article",
    "title": "How we price a bathroom renovation | Renew",
    "description": "What drives the price of a bathroom renovation.",
    "image": "https://blog.renew.example/static/uploadedImages/3f9c2b7e.jpg",
    "image_alt": "A tiled bathroom wall",
    "url": "https://blog.renew.example/how-we-price-a-bathroom-renovation",
    "site_name": "Renew",
    "locale": "en"
  },
  "twitter": {
    "card": "summary_large_image",
    "title": "How we price a bathroom renovation | Renew",
    "description": "What drives the price of a bathroom renovation.",
    "image": "https://blog.renew.example/static/uploadedImages/3f9c2b7e.jpg",
    "image_alt": "A tiled bathroom wall"
  },
  "image": {
    "url": "https://blog.renew.example/static/uploadedImages/3f9c2b7e.jpg",
    "alt": "A tiled bathroom wall",
    "source": "cover"
  },
  "authors": [
    {
      "name": "Inès Duarte",
      "url": "https://ines-duarte.example",
      "same_as": [
        "https://github.com/ines-duarte"
      ]
    }
  ],
  "published_at": "2026-03-12T09:14:00Z",
  "modified_at": "2026-09-10T07:00:00Z",
  "fallbacks": {
    "title": "title",
    "description": "excerpt",
    "image": "cover",
    "canonical": "site"
  },
  "json_ld": {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "How we price a bathroom renovation",
    "description": "What drives the price of a bathroom renovation.",
    "image": [
      "https://blog.renew.example/static/uploadedImages/3f9c2b7e.jpg"
    ],
    "author": [
      {
        "@type": "Person",
        "name": "Inès Duarte",
        "url": "https://ines-duarte.example",
        "sameAs": [
          "https://github.com/ines-duarte"
        ]
      }
    ],
    "datePublished": "2026-03-12T09:14:00Z",
    "dateModified": "2026-09-10T07:00:00Z",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://blog.renew.example/how-we-price-a-bathroom-renovation"
    }
  }
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Article not found
Link to this route
GET/v1/site/{key}/sitemap

List the published URLs of a site, by id ascending, as an array of { url, modified_at, noindex }. The total is in the X-Total-Count header.

Access · Public · 200

Query parameters

page number · Optional
A whole number from 1. Default 1.
size number · Optional
25, 50, 100 or 500. Default 100.

Request example

Bash
curl "https://cms.example.com/v1/site/renew-blog/sitemap"

Example response

JSON
[
  {
    "url": "https://blog.renew.example/how-we-price-a-bathroom-renovation",
    "modified_at": "2026-09-10T07:00:00Z",
    "noindex": false
  },
  {
    "url": "https://blog.renew.example/choosing-tiles-for-a-small-bathroom",
    "modified_at": "2026-09-09T07:00:00Z",
    "noindex": true
  }
]

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 404 site_not_found
Link to this route

Content types

Define your own kind of content, like events or recipes. A user whose role can create and edit content types defines a type made of 1 to 50 ordered fields; the type then has its own entry routes.

GET/v1/content-type/

List all custom content types.

Access · Verified user · 200

Request example

Bash
curl "https://cms.example.com/v1/content-type/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
[
  {
    "id": 2,
    "key": "events",
    "name": "Events",
    "icon": "calendar",
    "fields": [
      {
        "key": "title",
        "label": "Title",
        "type": "text",
        "required": true,
        "unique": false,
        "default": null,
        "min": 3,
        "max": 120,
        "options": null,
        "relation": null
      },
      {
        "key": "starts_on",
        "label": "Starts on",
        "type": "date",
        "required": true,
        "unique": false,
        "default": null,
        "min": null,
        "max": null,
        "options": null,
        "relation": null
      },
      {
        "key": "capacity",
        "label": "Capacity",
        "type": "number",
        "required": true,
        "unique": false,
        "default": null,
        "min": 1,
        "max": 5000,
        "options": null,
        "relation": null
      }
    ],
    "created_at": "2026-09-02T08:30:00Z",
    "updated_at": "2026-10-20T14:05:00Z"
  }
]

Errors

  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
GET/v1/content-type/{key}

Get one content type with its fields.

Access · Verified user · 200

Request example

Bash
curl "https://cms.example.com/v1/content-type/events" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 2,
  "key": "events",
  "name": "Events",
  "icon": "calendar",
  "fields": [
    {
      "key": "title",
      "label": "Title",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 3,
      "max": 120,
      "options": null,
      "relation": null
    },
    {
      "key": "starts_on",
      "label": "Starts on",
      "type": "date",
      "required": true,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "capacity",
      "label": "Capacity",
      "type": "number",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 5000,
      "options": null,
      "relation": null
    },
    {
      "key": "online",
      "label": "Online",
      "type": "boolean",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "category",
      "label": "Category",
      "type": "select",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": [
        "Workshop",
        "Talk",
        "Open day"
      ],
      "relation": null
    },
    {
      "key": "cover",
      "label": "Cover",
      "type": "media",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    }
  ],
  "created_at": "2026-09-02T08:30:00Z",
  "updated_at": "2026-10-20T14:05:00Z"
}

Errors

  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 content_type_not_found
Link to this route
POST/v1/content-type/

Create a content type. Needs the permission "Create and edit content types".

Access · Needs permission · 201

Request body

key string · Required
2 to 40 characters. Lowercase letters, digits and hyphens. Can't be changed later.
name string · Required
Up to 100 characters.
icon string · Optional
Optional.
fields object[] · Required
1 to 50 fields, in order. See Field types.

Request example

Bash
curl -X POST "https://cms.example.com/v1/content-type/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{
  "key": "events",
  "name": "Events",
  "icon": "calendar",
  "fields": [
    {
      "key": "title",
      "label": "Title",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 3,
      "max": 120,
      "options": null,
      "relation": null
    },
    {
      "key": "starts_on",
      "label": "Starts on",
      "type": "date",
      "required": true,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "capacity",
      "label": "Capacity",
      "type": "number",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 5000,
      "options": null,
      "relation": null
    }
  ]
}'

Example response

JSON
{
  "id": 2,
  "key": "events",
  "name": "Events",
  "icon": "calendar",
  "fields": [
    {
      "key": "title",
      "label": "Title",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 3,
      "max": 120,
      "options": null,
      "relation": null
    },
    {
      "key": "starts_on",
      "label": "Starts on",
      "type": "date",
      "required": true,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "capacity",
      "label": "Capacity",
      "type": "number",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 5000,
      "options": null,
      "relation": null
    },
    {
      "key": "online",
      "label": "Online",
      "type": "boolean",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "category",
      "label": "Category",
      "type": "select",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": [
        "Workshop",
        "Talk",
        "Open day"
      ],
      "relation": null
    },
    {
      "key": "cover",
      "label": "Cover",
      "type": "media",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    }
  ],
  "created_at": "2026-09-02T08:30:00Z",
  "updated_at": "2026-10-20T14:05:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 403 missing_permission
  • 409 content_type_key_taken
Link to this route
PUT/v1/content-type/{key}

Replace the name, icon and fields of a type. The key never changes. Saved field keys and types can't change. Needs the permission "Create and edit content types".

Access · Needs permission · 200

Request body

name string · Required
Up to 100 characters.
icon string · Optional
Optional.
fields object[] · Required
1 to 50 fields, in order. See Field types.

Request example

Bash
curl -X PUT "https://cms.example.com/v1/content-type/events" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Events",
  "icon": "calendar",
  "fields": [
    {
      "key": "title",
      "label": "Title",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 3,
      "max": 120,
      "options": null,
      "relation": null
    },
    {
      "key": "starts_on",
      "label": "Starts on",
      "type": "date",
      "required": true,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "capacity",
      "label": "Capacity",
      "type": "number",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 5000,
      "options": null,
      "relation": null
    }
  ]
}'

Example response

JSON
{
  "id": 2,
  "key": "events",
  "name": "Events",
  "icon": "calendar",
  "fields": [
    {
      "key": "title",
      "label": "Title",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 3,
      "max": 120,
      "options": null,
      "relation": null
    },
    {
      "key": "starts_on",
      "label": "Starts on",
      "type": "date",
      "required": true,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "capacity",
      "label": "Capacity",
      "type": "number",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 5000,
      "options": null,
      "relation": null
    },
    {
      "key": "online",
      "label": "Online",
      "type": "boolean",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    },
    {
      "key": "category",
      "label": "Category",
      "type": "select",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": [
        "Workshop",
        "Talk",
        "Open day"
      ],
      "relation": null
    },
    {
      "key": "cover",
      "label": "Cover",
      "type": "media",
      "required": false,
      "unique": false,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    }
  ],
  "created_at": "2026-09-02T08:30:00Z",
  "updated_at": "2026-10-20T14:05:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 403 missing_permission
  • 404 content_type_not_found
  • 409 schema_incompatible Some existing entries don't fit the new fields. Nothing was changed.
Link to this route
DELETE/v1/content-type/{key}

Delete a content type. Only possible when it has no entries and no relation field points at it. Needs the permission "Delete content types".

Access · Needs permission · 204

Request example

Bash
curl -X DELETE "https://cms.example.com/v1/content-type/events" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

Plain text
204 No Content

Errors

  • 401 You must be logged in to access this resource.
  • 403 missing_permission
  • 404 content_type_not_found
  • 409 content_type_has_entries
  • 409 content_type_referenced
Link to this route

Entries

Read and write the content of a custom type. Each route needs the matching content permission of the key creator's role.

GET/v1/content-type/{key}/entry

List entries of a type, one page at a time. The response is an object with items, total, page and size, not a bare array like articles.

Access · Verified user · 200

Query parameters

page integer · Optional
1 or higher. Default 1.
size integer · Optional
One of 5, 25, 50 or 100. Default 25.
sort string · Optional
id, created_at or updated_at, then :asc or :desc. For example updated_at:desc.

Request example

Bash
curl "https://cms.example.com/v1/content-type/events/entry" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "items": [
    {
      "id": 31,
      "content_type": "events",
      "data": {
        "title": "Open day",
        "starts_on": "2026-11-14",
        "capacity": 120,
        "online": false,
        "category": "Open day",
        "cover": 4
      },
      "created_by": 1,
      "updated_by": 1,
      "created_at": "2026-10-20T14:05:00Z",
      "updated_at": "2026-10-22T09:41:00Z",
      "media": {
        "cover": {
          "id": 4,
          "filename": "north-wall.jpg",
          "width": 1600,
          "height": 1067,
          "size": 3900000,
          "thumbnail_url": "/static/uploadedImages/3f9c-thumb.jpg"
        }
      },
      "relations": {}
    }
  ],
  "total": 1,
  "page": 1,
  "size": 25
}

Errors

  • 400 Invalid page, size or sort.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 content_type_not_found
Link to this route
POST/v1/content-type/{key}/entry

Create an entry.

Access · Verified user · 201

Request body

data object · Required
Keys are the type's field keys. For events: title, starts_on, capacity, online, category and cover.

Request example

Bash
curl -X POST "https://cms.example.com/v1/content-type/events/entry" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"data":{"title":"Open day","starts_on":"2026-11-14","capacity":120,"online":false,"category":"Open day","cover":4}}'

Example response

JSON
{
  "id": 31,
  "content_type": "events",
  "data": {
    "title": "Open day",
    "starts_on": "2026-11-14",
    "capacity": 120,
    "online": false,
    "category": "Open day",
    "cover": 4
  },
  "created_by": 1,
  "updated_by": 1,
  "created_at": "2026-10-20T14:05:00Z",
  "updated_at": "2026-10-22T09:41:00Z",
  "media": {
    "cover": {
      "id": 4,
      "filename": "north-wall.jpg",
      "width": 1600,
      "height": 1067,
      "size": 3900000,
      "thumbnail_url": "/static/uploadedImages/3f9c-thumb.jpg"
    }
  },
  "relations": {}
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 content_type_not_found
  • 409 invalid_entry: title must be unique
  • 422 invalid_entry: capacity must be at most 5000
Link to this route
GET/v1/content-type/{key}/entry/{id}

Get one entry.

Access · Verified user · 200

The example uses resource ID 31.

Request example

Bash
curl "https://cms.example.com/v1/content-type/events/entry/31" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 31,
  "content_type": "events",
  "data": {
    "title": "Open day",
    "starts_on": "2026-11-14",
    "capacity": 120,
    "online": false,
    "category": "Open day",
    "cover": 4
  },
  "created_by": 1,
  "updated_by": 1,
  "created_at": "2026-10-20T14:05:00Z",
  "updated_at": "2026-10-22T09:41:00Z",
  "media": {
    "cover": {
      "id": 4,
      "filename": "north-wall.jpg",
      "width": 1600,
      "height": 1067,
      "size": 3900000,
      "thumbnail_url": "/static/uploadedImages/3f9c-thumb.jpg"
    }
  },
  "relations": {}
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 entry_not_found
  • 404 content_type_not_found
Link to this route
PUT/v1/content-type/{key}/entry/{id}

Replace the data of an entry.

Access · Verified user · 200

Request body

data object · Required
Keys are the type's field keys. For events: title, starts_on, capacity, online, category and cover.

The example uses resource ID 31.

Request example

Bash
curl -X PUT "https://cms.example.com/v1/content-type/events/entry/31" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"data":{"title":"Open day","starts_on":"2026-11-14","capacity":150,"online":false,"category":"Open day","cover":4}}'

Example response

JSON
{
  "id": 31,
  "content_type": "events",
  "data": {
    "title": "Open day",
    "starts_on": "2026-11-14",
    "capacity": 150,
    "online": false,
    "category": "Open day",
    "cover": 4
  },
  "created_by": 1,
  "updated_by": 1,
  "created_at": "2026-10-20T14:05:00Z",
  "updated_at": "2026-10-22T09:41:00Z",
  "media": {
    "cover": {
      "id": 4,
      "filename": "north-wall.jpg",
      "width": 1600,
      "height": 1067,
      "size": 3900000,
      "thumbnail_url": "/static/uploadedImages/3f9c-thumb.jpg"
    }
  },
  "relations": {}
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 entry_not_found
  • 404 content_type_not_found
  • 409 invalid_entry: title must be unique
  • 422 invalid_entry: capacity must be at most 5000
Link to this route
DELETE/v1/content-type/{key}/entry/{id}

Delete an entry.

Access · Verified user · 204

The example uses resource ID 31.

Request example

Bash
curl -X DELETE "https://cms.example.com/v1/content-type/events/entry/31" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

Plain text
204 No Content

Errors

  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
  • 404 entry_not_found
  • 404 content_type_not_found
Link to this route

Built-in types

The fields of Articles, Authors, Sites, Media and Users, in the same shape as the fields of a content type.

GET/v1/builtin-type/

List the built-in types (Articles, Authors, Sites, Media, Users) and their fields. Keys are article, author, site, media and user. Needs the permission "View content types".

Access · Needs permission · 200

Request example

Bash
curl "https://cms.example.com/v1/builtin-type/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
[
  {
    "key": "article",
    "name": "Articles",
    "fields": [
      {
        "key": "title",
        "label": "Title",
        "type": "text",
        "required": true,
        "unique": false,
        "default": null,
        "min": 3,
        "max": 200,
        "options": null,
        "relation": null
      },
      {
        "key": "slug",
        "label": "Slug",
        "type": "text",
        "required": true,
        "unique": true,
        "default": null,
        "min": null,
        "max": null,
        "options": null,
        "relation": null
      },
      {
        "key": "body",
        "label": "Body",
        "type": "richtext",
        "required": false,
        "unique": false,
        "default": null,
        "min": null,
        "max": null,
        "options": null,
        "relation": null
      }
    ]
  },
  {
    "key": "author",
    "name": "Authors",
    "fields": [
      {
        "key": "name",
        "label": "Name",
        "type": "text",
        "required": true,
        "unique": false,
        "default": null,
        "min": 1,
        "max": 100,
        "options": null,
        "relation": null
      },
      {
        "key": "slug",
        "label": "Slug",
        "type": "text",
        "required": true,
        "unique": true,
        "default": null,
        "min": null,
        "max": null,
        "options": null,
        "relation": null
      }
    ]
  }
]

Errors

  • 401 You must be logged in to access this resource.
  • 403 missing_permission
Link to this route
GET/v1/builtin-type/{key}

Get one built-in type. Keys are article, author, site, media and user. Needs the permission "View content types".

Access · Needs permission · 200

Request example

Bash
curl "https://cms.example.com/v1/builtin-type/author" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "key": "author",
  "name": "Authors",
  "fields": [
    {
      "key": "name",
      "label": "Name",
      "type": "text",
      "required": true,
      "unique": false,
      "default": null,
      "min": 1,
      "max": 100,
      "options": null,
      "relation": null
    },
    {
      "key": "slug",
      "label": "Slug",
      "type": "text",
      "required": true,
      "unique": true,
      "default": null,
      "min": null,
      "max": null,
      "options": null,
      "relation": null
    }
  ]
}

Errors

  • 401 You must be logged in to access this resource.
  • 403 missing_permission
  • 404 builtin_type_not_found
Link to this route

Media

The image library. One image can be used in many articles.

GET/v1/media/

List images.

Access · Verified user · 200

Query parameters

q string · Optional
Search text.
hash string · Optional
SHA-256 of the content, lowercased.
filter string · Optional
all, unused or duplicates. Default all.
sort string · Optional
newest, oldest, name, largest or total_size. Default newest.
variants string · Optional
with or without. Default both.
page number · Optional
A whole number from 1. Default 1.
size number · Optional
5, 25, 50 or 100. Default 25.

Request example

Bash
curl "https://cms.example.com/v1/media/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "items": [
    {
      "id": 4,
      "filename": "north-wall.jpg",
      "url": "/static/uploadedImages/3f9c2b7e-5d1a-4c8e-9b0f-6a2d4e8c1b73.jpg",
      "size": 3900000,
      "content_type": "image/jpeg",
      "width": 4032,
      "height": 3024,
      "sha256": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
      "uploaded_by": "marta",
      "created_at": "2026-09-10T07:00:00Z",
      "used_in": 2,
      "duplicate": false
    }
  ],
  "total": 1,
  "page": 1,
  "size": 25,
  "counts": {
    "all": 1,
    "unused": 0,
    "duplicates": 0
  }
}

Errors

  • 400 The media query is invalid.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
GET/v1/media/{id}

Get one image, with the same fields as an item of the list.

Access · Verified user · 200

The example uses resource ID 4.

Request example

Bash
curl "https://cms.example.com/v1/media/4" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 4,
  "filename": "north-wall.jpg",
  "url": "/static/uploadedImages/3f9c2b7e-5d1a-4c8e-9b0f-6a2d4e8c1b73.jpg",
  "size": 3900000,
  "content_type": "image/jpeg",
  "width": 4032,
  "height": 3024,
  "sha256": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
  "uploaded_by": "marta",
  "created_at": "2026-09-10T07:00:00Z",
  "used_in": 2,
  "duplicate": false
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Image not found
  • 403 You must verify your account to access this resource.
Link to this route
POST/v1/media/

Upload an image (multipart).

Access · Verified user · 201

Request body

file file · Required
PNG, JPEG, WEBP or SVG.

Request example

Bash
curl -X POST "https://cms.example.com/v1/media/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -F "file=@north-wall.jpg"

Example response

JSON
{
  "id": 4,
  "filename": "north-wall.jpg",
  "url": "/static/uploadedImages/3f9c2b7e-5d1a-4c8e-9b0f-6a2d4e8c1b73.jpg",
  "size": 3900000,
  "content_type": "image/jpeg",
  "width": 4032,
  "height": 3024,
  "sha256": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
  "uploaded_by": "marta",
  "created_at": "2026-09-10T07:00:00Z",
  "used_in": 2,
  "duplicate": false
}

Errors

  • 400 the image could not be read
  • 401 You must be logged in to access this resource.
  • 413 the file exceeds the maximum upload size
  • 415 the file must be a PNG, JPEG, WEBP, or SVG image
  • 403 You must verify your account to access this resource.
Link to this route
PATCH/v1/media/{id}

Rename an image. The URL stays the same.

Access · Verified user · 200

Request body

filename string · Required
The new filename.

The example uses resource ID 4.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/media/4" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"filename":"north-wall-01.jpg"}'

Example response

JSON
{
  "id": 4,
  "filename": "north-wall-01.jpg",
  "url": "/static/uploadedImages/3f9c2b7e-5d1a-4c8e-9b0f-6a2d4e8c1b73.jpg",
  "size": 3900000,
  "content_type": "image/jpeg",
  "width": 4032,
  "height": 3024,
  "sha256": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
  "uploaded_by": "marta",
  "created_at": "2026-09-10T07:00:00Z",
  "used_in": 2,
  "duplicate": false
}

Errors

  • 400 Enter a filename.
  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Image not found
  • 403 You must verify your account to access this resource.
Link to this route
DELETE/v1/media/{id}

Delete an image. Articles that use it show a broken image.

Access · Verified user · 204

The example uses resource ID 4.

Request example

Bash
curl -X DELETE "https://cms.example.com/v1/media/4" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

Plain text
204 No Content

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Image not found
  • 403 You must verify your account to access this resource.
Link to this route
POST/v1/media/merge

Merge identical copies into one image.

Access · Verified user · 200

Request body

keep_id number · Required
Greater than 0. The image to keep.
merge_ids number[] · Required
At least 1, each greater than 0. Identical copies to delete. Articles switch to the kept image.

Request example

Bash
curl -X POST "https://cms.example.com/v1/media/merge" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"keep_id":4,"merge_ids":[9,11]}'

Example response

JSON
{
  "articles_updated": 5,
  "sites_updated": 1,
  "merged": 2
}

Errors

  • 400 Choose an image to keep and at least one other image to merge into it.
  • 401 You must be logged in to access this resource.
  • 409 Some of the images to merge changed. Refresh and try again.
  • 403 You must verify your account to access this resource.
Link to this route
GET/v1/media/{id}/usage

List the articles, authors and sites that use an image, with the places where each one uses it.

Access · Verified user · 200

The example uses resource ID 4.

Request example

Bash
curl "https://cms.example.com/v1/media/4/usage" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
[
  {
    "type": "article",
    "id": 12,
    "title": "How we price a bathroom renovation",
    "published": true,
    "fields": [
      "body",
      "cover"
    ]
  },
  {
    "type": "author",
    "id": 2,
    "title": "Inès Duarte",
    "fields": [
      "avatar"
    ]
  },
  {
    "type": "site",
    "id": 1,
    "title": "Renew blog",
    "fields": [
      "default_social_image"
    ]
  }
]

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Image not found
  • 403 You must verify your account to access this resource.
Link to this route
GET/v1/media/purge-settings

Get the automatic duplicate purge settings. Needs the permission "View settings".

Access · Needs permission · 200

Request example

Bash
curl "https://cms.example.com/v1/media/purge-settings" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "auto_purge_enabled": true,
  "auto_purge_interval_days": 30,
  "last_purge_at": "2026-09-10T07:00:00Z",
  "last_purge_merged": 2,
  "last_purge_articles_updated": 5,
  "enabled_at": "2026-08-11T07:00:00Z",
  "next_purge_at": "2026-10-09T07:00:00Z"
}

Errors

  • 401 You must be logged in to access this resource.
  • 403 missing_permission
Link to this route
PATCH/v1/media/purge-settings

Turn the automatic purge on or off, or change its interval. Needs the permission "Edit general settings".

Access · Needs permission · 200

Request body

auto_purge_enabled boolean · Optional
Leave out to keep the current value.
auto_purge_interval_days number · Optional
1 to 365. Leave out to keep the current value.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/media/purge-settings" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"auto_purge_enabled":true,"auto_purge_interval_days":30}'

Example response

JSON
{
  "auto_purge_enabled": true,
  "auto_purge_interval_days": 30,
  "last_purge_at": "2026-09-10T07:00:00Z",
  "last_purge_merged": 2,
  "last_purge_articles_updated": 5,
  "enabled_at": "2026-08-11T07:00:00Z",
  "next_purge_at": "2026-10-09T07:00:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 Enter a whole number of days between 1 and 365.
  • 401 You must be logged in to access this resource.
  • 403 missing_permission
Link to this route
GET/v1/media/purge-preview

Preview what a purge would merge. Nothing changes. Needs the permission "Delete files".

Access · Needs permission · 200

Request example

Bash
curl "https://cms.example.com/v1/media/purge-preview" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "groups": 1,
  "copies": 2,
  "articles": 5,
  "list": [
    {
      "keep_id": 4,
      "filename": "north-wall.jpg",
      "url": "/static/uploadedImages/3f9c2b7e-5d1a-4c8e-9b0f-6a2d4e8c1b73.jpg",
      "used_in": 5,
      "merged": 2
    }
  ],
  "more": 0,
  "fingerprint": "9c1f5e0a7d3b"
}

Errors

  • 401 You must be logged in to access this resource.
  • 403 missing_permission
Link to this route
POST/v1/media/purge

Merge every group of identical copies. Send the preview fingerprint to refuse a changed library. failed_groups counts groups that could not be purged; the others were still purged. Needs the permission "Delete files".

Access · Needs permission · 200

Request body

fingerprint string · Optional
The fingerprint of the preview. Without it, the purge runs on the current library.

Request example

Bash
curl -X POST "https://cms.example.com/v1/media/purge" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"fingerprint":"9c1f5e0a7d3b"}'

Example response

JSON
{
  "groups_total": 1,
  "groups_purged": 1,
  "merged": 2,
  "articles_updated": 5,
  "sites_updated": 1,
  "authors_updated": 0,
  "failed_groups": 0
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 409 The library changed, so nothing was purged. Check the new summary and try again.
  • 409 A purge is already running.
  • 401 You must be logged in to access this resource.
  • 403 missing_permission
Link to this route

Sites and authors

Read the sites and authors your content belongs to. Creating and changing them needs a session.

GET/v1/site/

List the sites, the default first and then by name, each with its article count. Without page or size every matching site is returned; the number of matching sites is in the X-Total-Count header.

Access · Verified user · 200

Query parameters

page number · Optional
A whole number from 1. Default 1.
size number · Optional
5, 25, 50 or 100. Default 25.
q string · Optional
Up to 200 characters, matched in the name, the key or the base URL, ignoring case and accents.

Request example

Bash
curl "https://cms.example.com/v1/site/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
[
  {
    "id": 1,
    "name": "Renew blog",
    "key": "renew-blog",
    "base_url": "https://blog.renew.example",
    "default_social_image_id": 4,
    "default_robots": "index",
    "locale": "en",
    "is_default": true,
    "article_count": 30,
    "site_name": "Renew",
    "title_template": "%title% | %site%",
    "default_description": "Notes from a renovation site."
  },
  {
    "id": 2,
    "name": "Renew shop",
    "key": "renew-shop",
    "base_url": "https://shop.renew.example",
    "default_social_image_id": null,
    "default_robots": "noindex",
    "locale": null,
    "is_default": false,
    "article_count": 4,
    "site_name": "",
    "title_template": "%title% - %site%",
    "default_description": ""
  }
]

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
GET/v1/author/

List the authors by name, each with its article count. The total is also in the X-Total-Count header.

Access · Verified user · 200

Query parameters

page number · Optional
A whole number from 1. Default 1.
size number · Optional
5, 25, 50 or 100. Default 25.
q string · Optional
Up to 200 characters, matched in the name or the slug.

Request example

Bash
curl "https://cms.example.com/v1/author/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "items": [
    {
      "id": 2,
      "name": "Inès Duarte",
      "slug": "ines-duarte",
      "bio": "Site manager and restoration carpenter.",
      "avatar_id": null,
      "website": "https://ines-duarte.example",
      "social_links": [],
      "user_id": 3,
      "is_linked": true,
      "article_count": 9
    },
    {
      "id": 7,
      "name": "Camille Roche",
      "slug": "camille-roche",
      "bio": "Freelance writer on lime and stone.",
      "avatar_id": null,
      "website": null,
      "social_links": [],
      "user_id": null,
      "is_linked": false,
      "article_count": 3
    }
  ],
  "total": 2,
  "page": 1,
  "size": 25
}

Errors

  • 400 The page, size or search is not valid.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route

Users and invites

People who can sign in, and pending invitations.

GET/v1/user/

List users and invites.

Access · Verified user · 200

Request example

Bash
curl "https://cms.example.com/v1/user/" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
[
  {
    "id": 1,
    "kind": "user",
    "username": "marta",
    "display_name": "Marta Alves",
    "email": "marta@renew.example",
    "role": {
      "id": 1,
      "name": "Owner",
      "built_in": true,
      "locked": true
    },
    "status": "accepted",
    "created_at": "2026-01-05T08:30:00Z"
  },
  {
    "id": 7,
    "kind": "invite",
    "email": "lea.martin@renew.example",
    "role": {
      "id": 3,
      "name": "Writer",
      "built_in": true,
      "locked": false
    },
    "status": "pending",
    "created_at": "2026-09-10T07:00:00Z"
  }
]

Errors

  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
PATCH/v1/user/me

Update my profile.

Access · Verified user · 200

Request body

display_name string · Required
Up to 60 characters.

Request example

Bash
curl -X PATCH "https://cms.example.com/v1/user/me" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"display_name":"Marta Alves"}'

Example response

JSON
{
  "id": 1,
  "username": "marta",
  "email": "marta@renew.example",
  "is_verified": true,
  "created_at": "2026-01-05T08:30:00Z",
  "updated_at": "2026-09-10T07:00:00Z",
  "display_name": "Marta Alves"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 400 Display name must be 60 characters or fewer.
  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route
POST/v1/user/invite

Invite a user by email.

Access · Owner only · 201 · Rate limited

Request body

email string · Required
A valid email address.
role_id number · Optional
The id of the role to give. Absent or 0 means the Writer role. The Owner role is refused.

Request example

Bash
curl -X POST "https://cms.example.com/v1/user/invite" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…" \
  -H "Content-Type: application/json" \
  -d '{"email":"lea.martin@renew.example","role_id":3}'

Example response

JSON
{
  "id": 7,
  "kind": "invite",
  "email": "lea.martin@renew.example",
  "role": {
    "id": 3,
    "name": "Writer",
    "built_in": true,
    "locked": false
  },
  "status": "pending",
  "created_at": "2026-09-10T07:00:00Z",
  "expires_at": "2026-09-13T07:00:00Z"
}

Errors

  • 400 The request cannot be processed due to a mismatch in the format of the body.
  • 401 You must be logged in to access this resource.
  • 409 This address already has an account.
  • 409 There's already a pending invite for this address.
  • 403 missing_permission
  • 429 Too many requests. Please try again later.
Link to this route
DELETE/v1/user/invite/{id}

Cancel a pending invite.

Access · Owner only · 204 · Rate limited

The example uses resource ID 7.

Request example

Bash
curl -X DELETE "https://cms.example.com/v1/user/invite/7" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

Plain text
204 No Content

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Invite not found
  • 403 missing_permission
  • 429 Too many requests. Please try again later.
Link to this route
POST/v1/user/invite/{id}/renew

Renew an expired invite.

Access · Owner only · 200 · Rate limited

The example uses resource ID 7.

Request example

Bash
curl -X POST "https://cms.example.com/v1/user/invite/7/renew" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 7,
  "kind": "invite",
  "email": "lea.martin@renew.example",
  "role": {
    "id": 3,
    "name": "Writer",
    "built_in": true,
    "locked": false
  },
  "status": "pending",
  "created_at": "2026-09-10T07:00:00Z",
  "expires_at": "2026-09-13T07:00:00Z"
}

Errors

  • 400 The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).
  • 401 You must be logged in to access this resource.
  • 404 Invite not found
  • 409 This invite has already been accepted.
  • 403 missing_permission
  • 429 Too many requests. Please try again later.
Link to this route
GET/v1/auth/me

Get the current user. With a key, the key's owner.

Access · Verified user · 200

Request example

Bash
curl "https://cms.example.com/v1/auth/me" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "id": 1,
  "username": "marta",
  "email": "marta@renew.example",
  "is_verified": true,
  "created_at": "2026-01-05T08:30:00Z",
  "updated_at": "2026-09-10T07:00:00Z",
  "display_name": "Marta Alves",
  "author": null,
  "access": {
    "role": {
      "id": 1,
      "name": "Owner",
      "built_in": true,
      "locked": true
    },
    "permissions": [
      {
        "key": "content.read",
        "scope": "all"
      },
      {
        "key": "content.create",
        "scope": "all"
      },
      {
        "key": "content.update",
        "scope": "all"
      },
      {
        "key": "content.delete",
        "scope": "all"
      },
      {
        "key": "content.publish",
        "scope": "all"
      },
      {
        "key": "settings.view",
        "scope": "all"
      },
      {
        "key": "users.view",
        "scope": "all"
      },
      {
        "key": "content.update:article",
        "scope": "own"
      }
    ]
  }
}

Errors

  • 401 You must be logged in to access this resource.
Link to this route

Settings

Read the site settings, including the activity log retention.

GET/v1/settings

Get settings.

Access · Verified user · 200

Request example

Bash
curl "https://cms.example.com/v1/settings" \
  -H "Authorization: Bearer rcms_Kf3x9QwL0aBc…"

Example response

JSON
{
  "version": "v3.0.0-beta",
  "activity_retention_days": 90,
  "activity_retention_max_gb": 5,
  "activity_log_size_bytes": 3435973837,
  "activity_last_cleanup_at": "2026-09-10T03:00:00Z",
  "activity_last_cleanup_removed": 12,
  "activity_next_cleanup_at": "2026-09-11T03:00:00Z"
}

Errors

  • 401 You must be logged in to access this resource.
  • 403 You must verify your account to access this resource.
Link to this route

Public and sign-in routes

  • GET/v1/Hello world.
  • GET/v1/auth/registrationWhether registration is open.
  • POST/v1/auth/password-reset/confirmSet a new password with the emailed code.
  • GET/v1/auth/inviteCheck an invite code.
  • POST/v1/auth/invite/acceptAccept an invite.
  • GET/healthzPlain text "ok". Outside /v1.

System · owner only

These routes use a browser session. See your instance’s reference for details.

  • GET/v1/system/updateUpdate status
  • POST/v1/system/update/checkCheck for update
  • POST/v1/system/update/downloadDownload update
  • POST/v1/system/update/restartRestart
  • PATCH/v1/settingsChange the activity log retention

Sign in and account

These routes use a browser session. See your instance’s reference for details.

  • POST/v1/auth/loginLog in. Made for the browser. A key is ignored here, with no 403.
  • POST/v1/auth/logoutLog out. Made for the browser. A key is ignored here, with no 403.
  • POST/v1/auth/registerRegister. Made for the browser. A key is ignored here, with no 403.
  • POST/v1/auth/verifyVerify email
  • DELETE/v1/auth/registerCancel registration
  • POST/v1/auth/password-resetReset password. Made for the browser. A key is ignored here, with no 403.

API key management

These routes use a browser session. See your instance’s reference for details.

  • GET/v1/api-keyList keys
  • POST/v1/api-keyCreate a key
  • DELETE/v1/api-key/{id}Revoke a key

Sites and authors writes

These routes use a browser session. See your instance’s reference for details.

  • POST/v1/site/Create a site
  • PATCH/v1/site/{id}Edit a site
  • PATCH/v1/site/{id}/defaultMake a site the default
  • DELETE/v1/site/{id}Delete a site, moving its articles with reassign_to
  • POST/v1/author/Create an author
  • PATCH/v1/author/{id}Edit an author, or your own author as a verified user
  • DELETE/v1/author/{id}Delete an author, moving its articles with reassign_to
  • POST/v1/author/meCreate your own author profile, as any verified user

Image variants

These routes use a browser session. See your instance’s reference for details.

  • GET/v1/image-variants/List variants
  • POST/v1/image-variants/Create a variant
  • PUT/v1/image-variants/{name}Replace a variant
  • PATCH/v1/image-variants/{name}Update a variant
  • DELETE/v1/image-variants/{name}Delete a variant
  • POST/v1/image-variants/{name}/purgePurge the cache of a variant
  • GET/v1/image-variants/cacheImage cache status
  • POST/v1/image-variants/cache/purgePurge the image cache
  • GET/v1/media/{id}/variantsList the variants of an image
  • POST/v1/media/{id}/variantsAdd variants to an image
  • POST/v1/media/{id}/variants/{name}Generate one variant of an image
  • DELETE/v1/media/{id}/variants/{name}Delete one variant of an image

Activity

These routes use a browser session. See your instance’s reference for details.

  • GET/v1/activityList activity events
  • GET/v1/activity/summaryActivity summary, owner and admin
  • GET/v1/activity/exportExport activity as CSV, owner and admin