API Documentation
Integration reference for connecting an analytics or CRM platform to SeniorLiving.News.
SeniorLiving.News can exchange data with one connected platform through two channels: export endpoints hosted on this site that the platform pulls from, and an ingest contract the platform implements so the site can push events to it in near real time. Both channels are disabled unless the site operator has configured a connection; there is no public or anonymous access to any of the data described here.
Authentication
Every request in both directions carries the same shared secret, arranged with the site operator, as a bearer token:
Authorization: Bearer <token>
Requests to the export endpoints with a missing or invalid token — or while no connection is configured — receive 404 Not Found, deliberately indistinguishable from the endpoint not existing.
Export endpoints (hosted by SeniorLiving.News)
GET https://seniorliving.news/api/export/status
Connection test. Verifies the bearer token against an active connection and nothing else — it reads no data and has no side effects, so it is safe to poll. Use this as the “test path” when configuring a platform's connection form.
{ "ok": true }GET https://seniorliving.news/api/export/events
Raw first-party analytics events (pageviews, link clicks, engagement pings), paginated by an exact integer cursor. Events contain no personally identifying information — that is enforced when events are captured, not filtered at export time.
| Parameter | Type | Description |
|---|---|---|
| after_id | integer ≥ 0 | Return events with id strictly greater than this. Default 0 (start from the beginning). |
| limit | integer 1–1000 | Maximum events per page. Default 500. |
{
"events": [
{
"id": 4182,
"occurred_at": "2026-08-03T14:07:11.402Z",
"event_type": "pageview",
"visitor_id": "9f2c4a1e77b04d1c",
"session_id": "b81d02c6a4e94f02",
"path": "/briefing",
"referrer": "https://news.google.com/",
"props": null
}
],
"next_after_id": 4182
}Pass next_after_id back as after_id to fetch the next page. When events comes back empty, next_after_id equals the cursor you sent — you are caught up. Ids are gap-free per row but not guaranteed contiguous; treat the cursor as opaque. A malformed query returns 400.
GET https://seniorliving.news/api/export/rollups
Daily metric rollups, computed on demand for a UTC date range. Nothing is precomputed or cached, so prefer modest ranges.
| Parameter | Type | Description |
|---|---|---|
| from | YYYY-MM-DD | First UTC day, inclusive. Must be a real calendar date. |
| to | YYYY-MM-DD | Last UTC day, inclusive. Must be ≥ from; the whole span may cover at most 92 days. |
{
"rollups": [
{
"date": "2026-08-03",
"source": "seniorliving.news",
"pageviews": 412,
"unique_visitors": 63,
"new_visitors": 9,
"sessions": 120,
"issue_number": 84,
"top_pages": [{ "path": "/briefing", "views": 88 }],
"link_clicks": 57,
"avg_engagement_seconds": 74,
"llm_usage": {
"calls": 6,
"failures": 1,
"by_model": [
{
"model": "nvidia/nemotron-3-ultra-550b-a55b:free",
"calls": 5,
"failures": 1,
"prompt_tokens": 60321,
"completion_tokens": 24110
}
]
},
"ga4": null
}
]
}top_pages lists at most ten paths by pageviews. avg_engagement_seconds is null on days with no engagement events. ga4 is reserved for Google Analytics figures and is currently always null. A quiet day returns zeros — the absence of a rollup, not zeros, signals a problem. A malformed or oversized range returns 400.
Ingest contract (implemented by the connected platform)
The connected platform exposes two endpoints under a base URL of its choosing. SeniorLiving.News calls them with the same bearer token.
POST {base}/v1/events
The site pushes events in JSON batches of up to 100. Each event carries a UUID id that serves as an idempotency key — retries can redeliver a batch, so the receiver must deduplicate on it.
[
{
"id": "5f0f9a3e-1c2b-4a6d-9e8f-0b1c2d3e4f5a",
"type": "newsletter.signup",
"occurred_at": "2026-08-03T14:03:22.512Z",
"payload": { … }
}
]Any 2xx response means the entire batch is durably accepted. Any other response — or a network failure, or exceeding the 15-second request timeout — causes the site to retry the batch with backoff: after 1 minute, 10 minutes, 1 hour, 6 hours, then every 24 hours, giving up after 20 attempts. Delivery is near-real-time when the receiver is healthy and self-heals after an outage.
Newsletter events
newsletter.signup, newsletter.confirmed, newsletter.unsubscribed, and newsletter.bounced each carry the subscriber's contact record as the payload:
{
"email": "pat@example.com",
"first_name": "Pat",
"last_name": "Rivera",
"zip": "19103",
"prefs": {
"email": {
"briefings": "daily",
"puzzles": "daily",
"onThisDay": "weekly",
"local": "off"
},
"sms": { "enabled": false }
},
"status": "confirmed",
"age_range": "65_74",
"gender": null,
"gender_self": null,
"categories": ["health", "travel"],
"profile_completed_at": "2026-08-03T15:12:09.000Z",
"created_at": "2026-08-01T14:03:22.512Z",
"confirmed_at": "2026-08-01T14:05:10.104Z",
"unsubscribed_at": null
}| Parameter | Type | Description |
|---|---|---|
| status | enum | pending · confirmed · unsubscribed · bounced |
| prefs.email.* | enum | Cadence per item: off · daily · weekly |
| age_range | enum | null | under_55 · 55_64 · 65_74 · 75_84 · 85_plus |
| gender | enum | null | woman · man · non_binary · self_described (free text then in gender_self) |
| categories | string[] | Any of: health, benefits, money, housing, caregiving, technology, travel, food |
| phone | string (absent by default) | Present only when the subscriber opted into SMS and provided a number. |
Analytics events
analytics.daily_rollup carries one UTC day's metrics — the payload shape is identical to a single entry in the export rollups endpoint above. One rollup is pushed per completed UTC day.
GET {base}/v1/llm-key
Lets the platform manage the site's language-model API key. The site fetches it only when no key is configured locally, and caches the response for 15 minutes.
{ "provider": "openrouter", "key": "sk-or-…", "expires_at": null }Any non-200 response makes the site treat the managed key as unavailable and fall back to its reserve content. On a 401 from the LLM provider the site discards its cached key, refetches once, and retries once.
Data & privacy
- Raw analytics events never contain personal information; that rule is enforced when events are recorded.
- Contact records travel only inside
newsletter.*events, only over HTTPS, and only to the operator-configured endpoint. - Phone numbers are shared only for subscribers who opted into SMS. Site-internal tokens (confirmation, unsubscribe, profile links) never leave the site.
Questions about integrating, or need credentials? Contact the site operator. This page documents the contract as currently deployed; breaking changes will be versioned under a new path prefix.