API Reference
Xenith's public API lets you read and write your own data — intentions, focus sessions, and dimension scores — from your own scripts, tools, or integrations. It's your data; the API just gives you a way to reach it programmatically.
Authentication
Create an API key in Settings → API access. The raw key is shown once, at creation — store it somewhere safe, since Xenith only ever stores its hash.
Send it as a bearer token on every request:
curl https://xenith.life/api/v1/intentions \
-H "Authorization: Bearer xnth_live_..."
Requests without a valid key get 401 Unauthorized. You can revoke a key at
any time from the same Settings page — it stops working immediately.
Base URL
https://xenith.life/api/v1
Rate limits
Each key is limited to 60 requests per minute, counted in fixed
one-minute windows. The limit is enforced atomically, so parallel requests
can't exceed it. Every response from an authenticated request — including
429s — carries these headers:
| Header | Value |
|---|---|
X-RateLimit-Limit | Requests allowed per window (60) |
X-RateLimit-Remaining | Requests left in the current window (never below 0) |
X-RateLimit-Reset | Unix time (seconds) when the window resets |
Retry-After | On 429 only: seconds to wait before retrying |
Going over returns 429 with { "error": "rate_limited" }. Wait for
Retry-After seconds (or until X-RateLimit-Reset) before retrying. Response
bodies also include a remaining field with the same count as
X-RateLimit-Remaining.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1790000040
Retry-After: 23
Errors
Errors are always a JSON body with an error field:
| Status | Meaning |
|---|---|
400 | Invalid request body or query parameters |
401 | Missing or invalid API key |
403 | Your key doesn't have the required scope |
429 | Rate limit exceeded |
500 | Something went wrong on Xenith's end |
Intentions
GET /api/v1/intentions
Requires scope intentions:read.
Query parameters (all optional):
| Param | Description |
|---|---|
scheduled_date | Filter to a single date (YYYY-MM-DD) |
completed | true or false |
limit | Max results, 1–100 (default 50) |
cursor | Pagination cursor — pass the previous response's next_cursor |
curl "https://xenith.life/api/v1/intentions?scheduled_date=2026-07-12" \
-H "Authorization: Bearer xnth_live_..."
{
"data": [ /* intention rows */ ],
"remaining": 59,
"next_cursor": null
}
POST /api/v1/intentions
Requires scope intentions:write.
Body:
| Field | Type | Required |
|---|---|---|
title | string (1–200 chars) | yes |
description | string (max 2000 chars) | no |
scheduled_date | string (YYYY-MM-DD) | no |
dimension | string | no |
estimated_minutes | integer (1–1440) | no |
curl -X POST https://xenith.life/api/v1/intentions \
-H "Authorization: Bearer xnth_live_..." \
-H "Content-Type: application/json" \
-d '{"title": "Write the quarterly review", "dimension": "Work"}'
Focus sessions
GET /api/v1/focus-sessions
Requires scope focus_sessions:read.
Query parameters (all optional): start, end (ISO timestamps to filter
started_at), limit (1–100, default 50), cursor.
POST /api/v1/focus-sessions
Requires scope focus_sessions:write. Logs a completed (or in-progress) focus
session — this is a record of actual timer usage, not a way to schedule a
future session, so started_at can't be more than 24 hours in the future.
Body:
| Field | Type | Required |
|---|---|---|
duration_minutes | integer (1–1440) | yes |
session_type | string | no |
notes | string (max 2000 chars) | no |
started_at | ISO timestamp | no |
completed_at | ISO timestamp | no |
Dimension scores
GET /api/v1/dimension-scores
Requires scope dimension_scores:read. Read-only — scores are recorded
through Xenith's own weekly check-in, not writable via the API.
Query parameters (all optional):
| Param | Description |
|---|---|
dimension | Filter to one life dimension |
history | 1 to return full history; omitted returns only the latest score per dimension |
Scopes
New API keys currently receive all available scopes:
intentions:read,intentions:writefocus_sessions:read,focus_sessions:writedimension_scores:read
Per-scope key creation is on the roadmap; for now, every key can do everything listed above.
CORS
All /api/v1/* endpoints allow cross-origin requests from any origin —
authentication is entirely via the Authorization header (never cookies), so
there's no ambient browser credential to protect against.