API
Web docs for the current API contract.
Admin Sync
Content Status
Mode: cache_db
Sync source hint: notion
Writing source hint: hey_world (hey_world_live)
Cached records: profiles=1, case_studies=1, posts=23, experiences=10
Last sync: ok=true, source=notion, code=ok, at=2026-02-28T19:18:20Z
Content Debug (Safe)
CONTENT_SYNC_SOURCE: notion
WRITING_SOURCE: hey_world
HEY_WORLD_URL: https://world.hey.com/johnnybutler/
NOTION_TOKEN present: true
NOTION_PROFILE_DB_ID present: true
NOTION_CASE_STUDIES_DB_ID present: true
NOTION_PROFILE_PAGE_ID present: true
NOTION_CV_DATABASE_ID present: true
Chat Runtime Status
Backend: openai
Ready: true
OPENAI_API_KEY present: true
OPENAI_MODEL: gpt-4.1-mini
Recent Sync Runs
- ok=true, source=notion, code=ok, at=2026-02-28T19:18:20Z
- ok=false, source=notion, code=invalid_token, at=2026-02-28T19:16:12Z
- ok=true, source=fixtures, code=ok, at=2026-02-28T19:16:08Z
- ok=true, source=fixtures, code=ok, at=2026-02-28T19:16:07Z
- ok=true, source=fixtures, code=ok, at=2026-02-28T19:16:06Z
Sync Configuration
CONTENT_SYNC_SOURCE:fixturesornotionWRITING_SOURCE:markdownorhey_worldCHAT_BACKEND:stuboropenaiOPENAI_API_KEY: required whenCHAT_BACKEND=openaiOPENAI_MODEL: optional (defaultgpt-4.1-mini)OPENAI_GROUNDED_MODE: optional (deterministicdefault, setgenerateto have OpenAI rewrite grounded context)ADMIN_CONTENT_SYNC_KEY: optional (required only when admin sync guard is enabled)NOTION_TOKEN,NOTION_PROFILE_DB_ID,NOTION_CASE_STUDIES_DB_ID: required for notion sync modeNOTION_PROFILE_PAGE_ID: optional profile page id (for admin/import tooling)NOTION_CV_DATABASE_ID: optional Notion CV database for experience sync (NOTION_CV_EXPERIENCE_DB_IDalso supported)
CHAT_BACKEND=openai OPENAI_API_KEY=sk-... CONTENT_SYNC_SOURCE=notion WRITING_SOURCE=hey_world bin/rails content:sync
API v1
Base path: /api/v1
Authentication
- If
API_V1_KEYis unset, v1 endpoints are open (dev-friendly default). - If
API_V1_KEYis set, send headerX-API-Key: <value>. - Invalid or missing key returns
401with:
{
"error": {
"code": "unauthorized",
"message": "Unauthorized"
}
}
Error Contract
Error responses use:
{
"error": {
"code": "<machine_code>",
"message": "<human_message>"
}
}
Malformed chat payloads return 400 with:
{
"error": {
"code": "invalid_request",
"message": "Invalid request payload"
}
}
Endpoints
GET /api/v1/content/profile
Returns profile content from the cache/fixture source.
Response:
{
"data": {
"name": "Johnny Butler",
"tagline": "Building useful software with fast feedback loops",
"bio": "Engineer focused on pragmatic delivery, clear process, and grounded AI systems.",
"location": "London"
}
}
GET /api/v1/content/case_studies
Returns case studies from the cache/fixture source.
Response:
{
"data": [
{
"title": "Customer Onboarding Refresh",
"summary": "Reduced signup drop-off by simplifying first-run setup.",
"outcome": "Activation up 18% in six weeks.",
"slug": "customer-onboarding-refresh"
}
]
}
GET /api/v1/content/posts
Returns writing posts from the cache/fixture source.
Response:
{
"data": [
{
"title": "Keeping CI Green",
"summary": "Treat CI red as stop-the-line, and fix in the same branch.",
"date": "2026-01-01",
"slug": "keeping-ci-green"
}
]
}
GET /api/v1/content/experiences
Returns CV experiences from cache source.
Response:
{
"data": [
{
"company": "Materials Market",
"role": "Head of Engineering",
"location": "Remote",
"start_date": "2021-11-01",
"end_date": "",
"current": true,
"summary": "Owns platform and operations."
}
]
}
POST /api/v1/chat/messages
Accepts a chat question and returns grounded answer + sources.
Request:
{
"message": {
"question": "What work has Johnny done?"
}
}
Response:
{
"data": {
"question": "What work has Johnny done?",
"answer": "Recent work includes...",
"error_code": null,
"sources": [
{
"label": "Content cache",
"path": "app/services/content/cache_store.rb",
"href": "/app/services/content/cache_store.rb"
}
]
}
}
Unsupported questions must return:
answer:"Not in the provided material."sources:[]- optional
error_codefor provider/runtime issues (for example:openai_rate_limited,openai_auth_failed,openai_timeout,openai_request_failed)
Notes
- Versioning follows
/api/v1namespace. - Contracts are enforced by request tests in
test/requests/api/v1. - Operational status endpoint:
GET /api/content/status(outside v1) returns sync/debug state used by/api. - Operational status includes
chat_status(backend/readiness/key-present/model) to verify OpenAI runtime wiring. - OpenAI backend defaults to deterministic grounded mode (
OPENAI_GROUNDED_MODE=deterministic) for stable answers; setgenerateto enable OpenAI rewriting.