Living Group · API Reference

API documentation

All endpoints below are served from the CMS at https://cms.yourdomain.com. Content is multi-tenant — every read must be scoped to a site.

Newsletter signup (public)

Called by the newsletter form on each website. The site is detected automatically from the request's Origin header (must match a registered site domain), so the form only sends the visitor's email.

POST /api/newsletter-signup Content-Type: application/json { "email": "user@example.com" }201 Created { "ok": true, "alreadySubscribed": false, "doc": { ... } } 200 OK (already subscribed) { "ok": true, "alreadySubscribed": true, "message": "..." } 400 Bad Request (invalid email or unknown origin)

Public content reads

Anonymous reads are only allowed when the request filters by a real site slug. Use this from the static sites to fetch published content.

GET /api/posts?where[tenant.slug][equals]=roducate GET /api/posts?where[tenant.slug][equals]=roducate&where[status][equals]=published GET /api/posts/{id} GET /api/pages?where[tenant.slug][equals]=living GET /api/categories?where[tenant.slug][equals]=ductour GET /api/tags?where[tenant.slug][equals]=roducate GET /api/media?where[tenant.slug][equals]=roducate GET /api/tenants (public: sites query by slug) GET /api/tenants?where[slug][equals]=roducate

Subscriber emails are never readable anonymously — see the admin section below.

Authentication (admin)

Log in to obtain a token. Pass it via the Authorization header or the payload-token cookie.

POST /api/users/login Content-Type: application/json { "email": "admin@liv.ing", "password": "your-password" } // response includes: { "token": "...", "user": { ... } }GET /api/users/me // current user POST /api/users/logout

Newsletter subscribers (admin)

Read, create and delete subscriber records. Admins are scoped to their own site; super-admins see everything.

GET /api/newsletter-subscribers?limit=50&sort=-createdAt POST /api/newsletter-subscribers Content-Type: application/json { "email": "user@example.com", "tenant": "roducate" } PATCH /api/newsletter-subscribers/{id} DELETE /api/newsletter-subscribers/{id}

Newsletter campaigns (admin)

Compose email campaigns in the dashboard and send them to every subscriber of a single site. Campaign content is built from reusable blocks (heading, text, button, image, divider, spacer) that render as standard HTML email components. A campaign can only be sent once, and only super-admins or admins of the campaign's own site may trigger the send.

GET /api/newsletter-campaigns?limit=50&depth=1 POST /api/newsletter-campaigns Content-Type: application/json { "name": "Spring Sale", "subject": "Spring Sale is live!", "tenant": "living", "content": [ { "blockType": "heading", "text": "Spring Sale is live!", "level": "h2", "align": "left" }, { "blockType": "text", "text": "Code SALE20 at checkout.", "align": "left" }, { "blockType": "button", "label": "Shop the sale", "url": "https://liv.ing/sale", "style": "primary", "align": "center" } ] } PATCH /api/newsletter-campaigns/{id} DELETE /api/newsletter-campaigns/{id} // copy into a new draft campaign: POST /api/newsletter-campaigns/{id}/duplicate

Sending renders the campaign body as an HTML newsletter and delivers it over SMTP. By default it goes to every subscriber of the campaign's site; pass an explicit recipients array to send only to a list of email addresses instead. Draft campaigns are marked as sent after the first send; sent campaigns can be resent at any time.

POST /api/newsletter-campaigns/{id}/send // authenticated; idempotent-blocked // send to everyone on the site: {} // send only to specific addresses: { "recipients": ["a@example.com", "b@example.com"] } 200 OK { "ok": true, "sent": 2, "failed": 0, "total": 2 } 401 Unauthorized (not signed in) 403 Forbidden (admin of another site) 404 Not Found 409 Conflict (already sent) 400 Bad Request (no subscribers, or no valid recipients)

Newsletter unsubscribe (public)

The one-click unsubscribe link embedded in every sent email. Removes the email from the given site and returns a confirmation page.

GET /api/newsletter-unsubscribe?email=user@example.com&tenant=living // returns an HTML confirmation page

Content management (admin)

The full CRUD API is available for every collection (posts, pages, media, categories, tags, users, tenants) and respects tenant scoping.

GET /api/posts?limit=10&depth=2 POST /api/posts PATCH /api/posts/{id} DELETE /api/posts/{id} POST /api/media // multipart form-data, {"_payload": "{\"alt\": \"...\"}"}

GraphQL

An interactive GraphQL playground is available, and all collections are exposed as queries/mutations with the same access rules.

GET /api/graphql (playground UI) POST /api/graphql (GraphQL API)