Beacon API Specification Base URL - https://beacon.sijibomi.com Purpose - Beacon accepts authenticated webhook-style event submissions and sends email notifications. - This service currently supports one programmatic write endpoint: POST /emit - The web UI endpoints are browser-oriented and use cookie sessions; they are not the primary integration surface for scripts or LLM agents. Authentication - API requests to POST /emit must include an Authorization header: Authorization: Bearer - Tokens are created in the Beacon web UI under /tokens - If the token is missing, malformed, or invalid, the request fails with HTTP 401 Content Type - Send JSON with header: Content-Type: application/json Endpoint: POST /emit - Path: /emit - Auth required: yes (Bearer token) - Purpose: create an event record and enqueue an email delivery job Request Body - title: string, required Human-readable event title. Empty or whitespace-only values are rejected. - message: string, optional Longer free-form event detail shown in the UI and email. - source: string, optional System or subsystem name, for example "nightly-backup" or "ml-training". - event: string, optional Event type name, for example "completed", "failed", or "started". - level: string, optional Allowed semantic values: - "info" - "warn" or "warning" -> normalized to "warn" - "danger", "critical", or "error" -> normalized to "danger" Any other value is treated as "info". - channel: string, optional Only "email" is supported in v1. If omitted, Beacon defaults it to "email". Any non-"email" value is rejected with HTTP 400. - metadata: object, optional Arbitrary JSON object with extra fields. Nested values are allowed if they are valid JSON. Successful Response - HTTP 200 - JSON body: { "status": "ok", "event_id": 42 } Error Responses - HTTP 400 - invalid JSON - missing or blank title - unsupported channel - HTTP 401 - missing Authorization header - invalid Authorization header - invalid token - HTTP 500 - internal persistence or authentication lookup failure Delivery Semantics - A successful POST /emit means the event was stored. - Beacon then enqueues an email job in Redis for asynchronous delivery. - Email sending may still fail after the HTTP 200 response if the queue or provider later encounters an error. - Delivery attempts and errors are visible in the web UI on the event detail page. Minimal Example curl -X POST https://beacon.sijibomi.com/emit \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"title":"hello from beacon"}' Full Example curl -X POST https://beacon.sijibomi.com/emit \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "source": "ml-training", "event": "completed", "title": "Training run finished", "message": "Resnet50 finished after 4h12m. Final val_acc = 0.927.", "level": "info", "channel": "email", "metadata": { "run_id": "rn_8a3f9c", "duration": "4h12m", "val_acc": 0.927, "checkpoint": "s3://models/rn_8a3f9c/best.pt" } }' Failure Example curl -X POST https://beacon.sijibomi.com/emit \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "title": "Backup failed", "message": "rsync exited with code 23", "level": "danger", "source": "nightly-backup", "metadata": {"host":"db-01","exit_code":23} }' Read-Only Public Endpoints - GET /health Lightweight liveness endpoint. Returns HTTP 200 with {"status":"ok"} if the HTTP app is up. - GET /heartbeat Deeper readiness-style endpoint. Checks app, SQLite, Redis, and queue connectivity. Returns HTTP 200 when all checks pass. Returns HTTP 503 when any dependency check fails. - GET /api-spec Returns this plain-text specification. - GET /openapi.json Returns the OpenAPI 3.1 JSON document for this service. Heartbeat Response Shape { "status": "ok", "timestamp": "2026-05-05T01:23:45Z", "checks": { "app": "ok", "db": "ok", "redis": "ok", "queue": "ok" } } Notes For LLM Agents - Use POST /emit for all programmatic notifications. - Always send a non-empty title. - Always send the Bearer token header. - Prefer level values "info", "warn", or "danger". - Do not send channel values other than "email". - Treat HTTP 200 as "event accepted and recorded", not necessarily "email already sent".