Use raw JSON or rendered HTML
Read published content without authentication or use the scoped management API for server-side publishing operations.
Public JSON
GET /api/public/:blog/posts
GET /api/public/:blog/posts/:slug
GET /api/public/:blog/redirectsThe list endpoint accepts these query parameters:
| Parameter | Meaning |
|---|---|
page | One-based page number; defaults to 1 |
pageSize | Results per page, capped at 100 |
search | Full-text search across published content |
category | Category slug filter |
limit | Deprecated alias for pageSize |
The list response contains blog, posts, categories, and pagination. Each post includes sanitized contentHtml, source contentMarkdown, author and category relationships, reading time, canonical metadata, and publication timestamps. Public clients therefore receive the full published body, not only a summary.
curl --fail \
"https://publish.example.com/api/public/fieldnotes/posts?page=1&pageSize=10"Individual post requests return blog and post. A request for an old published slug receives a permanent redirect after that slug changes. Missing publications and posts return 404.
The redirects endpoint returns the publication’s old and canonical slug pairs. Static framework integrations use this manifest to prebuild legacy paths instead of waiting for the first request.
Public JSON allows cross-origin reads and is sent with shared-cache guidance of 60 seconds plus stale revalidation. Do not use public endpoints for draft previews.
Rendered HTML
GET /api/rendered/:blog
GET /api/rendered/:blog/:slugThe publication route returns a semantic card listing. The post route returns a semantic article with sanitized body HTML, author information, stable pw-* classes, and the publication’s scoped custom CSS. Use these routes when the host wants ready-made markup but must control where and when it is fetched.
The rendered endpoint is also public, cross-origin readable, and cacheable. It returns fragments rather than a complete HTML document.
Private management API
Private operations live under /api/v1 and use a publication-scoped bearer token:
Authorization: Bearer pw_live_...| Method | Path | Required scope | Behavior |
|---|---|---|---|
GET | /api/v1/health | None | Database readiness and application version |
GET | /api/v1/blogs | content:read | Return the publication selected by the key |
GET | /api/v1/posts | content:read | List posts, including non-public states |
GET | /api/v1/posts/:id | content:read | Retrieve one post by UUID |
GET | /api/v1/posts/:id/revisions | content:read | List saved revisions, newest first |
POST | /api/v1/posts | content:write | Create a post |
PATCH | /api/v1/posts/:id | content:write | Update supplied fields |
POST | /api/v1/posts/:id/revisions/:revisionId/restore | content:write | Save the current version, then restore the selected revision |
DELETE | /api/v1/posts/:id | content:write | Archive the post; it does not delete the row |
GET | /api/v1/media | content:read | List media assets, post references, and quota usage |
GET | /api/v1/media/:id | content:read | Retrieve one media asset |
POST | /api/v1/media/uploads | content:write | Reserve quota and return a signed direct-upload request |
POST | /api/v1/media/:id/complete | content:write | Validate the stored upload and create sanitized variants |
POST | /api/v1/import?mode=preview&preserveStates=false | content:write | Stream a portable JSON v2 or ZIP import; mode=apply creates content |
DELETE | /api/v1/media/:id | content:write | Delete an asset that has no current post references |
The private list accepts search, status, page, and pageSize. Create requires blogId, authorId, title, and slug; optional fields have the same limits enforced by the SDK and CLI. Slugs contain lowercase letters, numbers, and single hyphens, with a maximum length of 120 characters.
Create and update operations render and sanitize Markdown before persistence. Restore applies content that Prosewire rendered and stored in an earlier revision. Every mutation creates an audit record.
A media upload has three steps. First, create a reservation with the publication UUID, filename, MIME type, and exact byte count. Second, send the unchanged body to the returned URL with the returned method and headers before expiresAt. Third, call the completion endpoint. Completion verifies the object metadata and file contents before making it available. Only JPEG, PNG, WebP, and AVIF are accepted. Uploads may also fail when their processed variants exceed the publication quota.
Expect 400 for invalid input, 401 for a missing or invalid key, 403 for an insufficient scope or publication boundary, and 404 for a missing post, revision, or media asset. Media reference and state conflicts return 409, quota failures return 413, and unavailable object storage returns 503. Other service failures return 500.
Keep management tokens on trusted servers. Browser applications should use the public JSON or rendered endpoints unless they are backed by a server that holds the token.
Portable import uses a streaming route and shared report/error schemas outside the buffered JSON HttpApi adapter. Preview performs validation without writes; apply defaults posts to drafts and never overwrites existing content. Import validation and quota failures return 400, collisions return 409, and infrastructure failures return 500. See portable import for envelope limits, state preservation, media, and retry policy.