Living Group · API ReferenceAPI 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]=roducateSubscriber 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/logoutNewsletter 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}/duplicateSending 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 pageContent 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)