Public read API
These unauthenticated routes expose active public publications and their published content. They return JSON except the RSS feed and XML sitemap.
Publication selector
Every route requires exactly one active publication selector:
{ "publication_slug": "engineering-notes" }
publication_id is also accepted. The public read API does not resolve browser hosts or paths; use /domain/resolve and /redirect/resolve where those lookups are needed.
Routes
| Route | Methods | Required fields | Optional fields | Success result |
|---|---|---|---|---|
/read/publication |
GET, POST |
Publication selector | — | public_publication. |
/read/home |
GET, POST |
Publication selector | category_slug, pagination |
Paginated public posts. |
/read/archive |
GET, POST |
Publication selector | year, month, pagination |
Archive facets and public posts. |
/read/search |
GET, POST |
Publication selector, q |
Pagination | Query and public posts. |
/read/categories |
GET, POST |
Publication selector | Pagination | Paginated categories. |
/read/category |
GET, POST |
Publication selector, category_slug |
Pagination | public_category and public posts. |
/read/tags |
GET, POST |
Publication selector | Pagination | Paginated tags. |
/read/tag |
GET, POST |
Publication selector, tag_slug |
Pagination | public_tag and public posts. |
/read/authors |
GET, POST |
Publication selector | Pagination | Paginated authors. |
/read/author |
GET, POST |
Publication selector, author_slug |
Pagination | public_author and public posts. |
/read/post |
GET, POST |
Publication selector, post_slug |
— | public_post. |
/read/page |
GET, POST |
Publication selector, page_slug |
— | public_page. |
/read/feed |
GET, POST |
Publication selector | site_url, post_path_prefix, limit |
RSS 2.0 XML. |
/read/sitemap |
GET, POST |
Publication selector | site_url, post_path_prefix, page_path_prefix |
XML sitemap. |
Public list routes use the pagination contract in the service guide. Lists include only published, public, unarchived posts; posts under inactive categories are also excluded. limit defaults to 50 and is capped at 200 for these JSON lists.
Publication and content reads
curl -sS https://api.blog.service.m7.org/v1/read/post \
-H 'Content-Type: application/json' \
-d '{"publication_slug":"engineering-notes","post_slug":"release-notes"}'
{
"status": 1,
"comment": "post loaded",
"data": {
"public_post": {
"slug": "release-notes",
"title": "Release notes",
"excerpt": "A summary.",
"body": "<h1>Release notes</h1>",
"body_format": "html",
"source_body_format": "markdown",
"visibility": "public",
"published_at": "2026-08-19 00:00:00.000000",
"category": { "slug": "updates", "name": "Updates" },
"tags": [{ "slug": "release-notes", "name": "Release Notes" }],
"authors": [{ "slug": "ada-lovelace", "name": "Ada Lovelace" }]
}
}
}
/read/post and /read/page return rendered HTML in body; source_body_format tells whether the stored body was Markdown or HTML. They permit published public and unlisted content, but not private content. Draft, review, scheduled, archived, disabled-publication, and inactive-category content returns 404.
Lists, archives, and search
/read/home accepts category_slug to select one active category. /read/archive accepts year from 1000 through 9998 and, only with year, month from 1 through 12. It returns archive and archive_periods alongside the normal paginated posts.
/read/search requires string q: one to 120 characters and at most eight distinct terms. All terms must match a post title, excerpt, or body. The result's query is the normalized query; results are ordered by relevance and then published date.
Each public post summary includes slug, title, nullable excerpt, nullable featured_media_id, nullable featured_media, nullable category, and ordered tags and authors. Public categories, tags, and authors include a post_count. Category summaries also include description, nullable summary, and optional featured media. Public author summaries include bio, external_url, and socials.
Feed and sitemap
/read/feed streams application/rss+xml; charset=UTF-8; /read/sitemap streams application/xml; charset=UTF-8. Both need a canonical site URL. Send site_url as an absolute http or https URL without a query string or fragment, or omit it to use a verified publication domain.
{
"publication_slug": "engineering-notes",
"site_url": "https://notes.example.com",
"post_path_prefix": "/posts",
"page_path_prefix": ""
}
If no site_url is supplied and the publication has no verified domain, these routes return 422. Path prefixes are optional, must be path-only values, and default to /posts for feed post links, /posts for sitemap post links, and an empty path for sitemap page links. Feed limit defaults to 50 and is capped at 100.