Sleek Coach Docs

API Reference

Reference for the Sleek Coach REST API: authentication, error format, rate limits, and the endpoint map.

Overview

Request and response bodies are not duplicated here. Run the API locally (make -C apps/api run) and use the live, always-current documentation:

Interactive docs are enabled in development only; they are disabled in staging and production.

Authentication

sequenceDiagram
    participant Client
    participant API
    participant DB

    Client->>API: POST /auth/register
    API->>DB: Create user
    API-->>Client: {access_token, refresh_token}

    Client->>API: GET /me (Bearer token)
    API->>API: Validate JWT
    API->>DB: Fetch user
    API-->>Client: User data

    Note over Client,API: When access token expires (15 min)

    Client->>API: POST /auth/refresh
    API->>DB: Validate refresh token
    API->>DB: Rotate refresh token
    API-->>Client: {new_access_token, new_refresh_token}

Token Lifecycle

Token type Expiry Usage
Access token 15 minutes Authorization: Bearer <token> on every request
Refresh token 7 days Exchange for a new token pair via POST /auth/refresh

Tokens are HS256 JWTs carrying sub, email, token_type, exp, iat, and jti. Refresh tokens are rotated on every use (the old token is revoked) and stored server-side as SHA-256 hashes with client IP and user agent. POST /auth/logout revokes one refresh token; POST /auth/logout-all revokes all of a user’s tokens. Token endpoints return {access_token, refresh_token, token_type: "bearer", expires_in}. Expiry defaults live in apps/api/app/config.py (access_token_expire_minutes, refresh_token_expire_days).

Error Handling

Errors use FastAPI’s standard shape:

{"detail": "Error message describing what went wrong"}

Validation failures return 422 with a list of {loc, msg, type} items in detail. Status codes in use: 200, 201, 204 (deletion), 400, 401 (with WWW-Authenticate: Bearer), 403, 404, 409, 422, 429, 500. Coach endpoints return generic 500 messages and never leak internal error details.

Rate Limiting

Rate limits are configured in apps/api/app/middleware/rate_limit.py (slowapi): a default of 100 requests per 60 seconds per client IP (rate_limit_requests / rate_limit_period settings) and a stricter AUTH_RATE_LIMIT of 5 requests per 15 minutes intended for auth endpoints. Note: the limiter and its 429 handler are registered on the app, but no route currently applies these limits, so they are configured rather than enforced.

Endpoint Map

All paths below are relative to /api/v1. “Auth” means a valid access token is required.

Authentication (app/auth/router.py)

Method and path Auth Purpose
POST /auth/register No Create account (returns token pair, 201)
POST /auth/login No Authenticate, return token pair
POST /auth/refresh No Rotate refresh token, return new pair
POST /auth/logout No Revoke the provided refresh token
POST /auth/logout-all Yes Revoke all refresh tokens for the user
POST /auth/change-password Yes Change password (verifies current)

Users (app/users/router.py)

Method and path Auth Purpose
GET /me Yes Current user with profile, goals, preferences
PATCH /me/profile Yes Partial profile update
PATCH /me/goals Yes Update fitness goals
PATCH /me/preferences Yes Update diet preferences
GET /me/export Yes GDPR data export
DELETE /me Yes Permanently delete account and data
GET /me/consents Yes List privacy consent records
POST /me/consents Yes Grant or update a consent
DELETE /me/consents/{consent_type} Yes Revoke a consent

Check-ins (app/checkins/router.py)

Method and path Auth Purpose
POST /checkins Yes Create or update a check-in (upsert by date, 201)
GET /checkins Yes List check-ins (from, to, limit, offset)
GET /checkins/latest Yes Most recent check-in or null
GET /checkins/trends Yes Weight trend with 7-day moving average (days)
POST /checkins/sync Yes Batch offline sync with conflict resolution

Nutrition (app/nutrition/router.py)

Method and path Auth Purpose
POST /nutrition/day Yes Create or update a nutrition day (upsert, 201)
GET /nutrition/day?date= Yes Nutrition for a date or null
GET /nutrition/range Yes Daily list or aggregate stats (from, to, aggregate)
DELETE /nutrition/day?date= Yes Delete a nutrition day (204)
POST /nutrition/calculate-targets Yes TDEE and macro targets (Mifflin-St Jeor)

Photos (app/photos/router.py)

Method and path Auth Purpose
POST /photos/presign Yes Presigned S3 upload URL (5 minute validity)
POST /photos/commit Yes Confirm upload, store metadata (201)
GET /photos Yes List photos with presigned download URLs
GET /photos/{photo_id} Yes Single photo
DELETE /photos/{photo_id} Yes Delete photo

Integrations (app/integrations/router.py)

Method and path Auth Purpose
POST /integrations/mfp/import Yes Import a MyFitnessPal export ZIP (max 50 MB, overwrite flag)

AI Coach (app/coach_ai/router.py)

Method and path Auth Purpose
POST /coach/chat Yes Chat with the coach (non-streaming)
POST /coach/chat/stream Yes Chat via Server-Sent Events
POST /coach/plan Yes Generate a weekly plan
GET /coach/insights Yes Pre-computed weekly insights

POST /coach/chat/stream returns text/event-stream. Each event is a JSON object with type and data; type is one of token, tool_start, tool_end, done, error. token.data and error.data are plain strings; the terminal done event carries:

{
  "session_id": "uuid",
  "confidence": 0.85,
  "data_gaps": [{"field": "...", "description": "...", "suggestion": "..."}],
  "disclaimers": ["..."],
  "tool_trace": [{"tool_name": "...", "latency_ms": 45, "cached": false}]
}

The non-streaming ChatResponse carries the same metadata plus message and tokens_used. The full streaming contract and its rules: AI_COACH.md and AI_CONVENTIONS.md.

Method and path Auth Purpose
GET /legal/privacy-policy No Privacy policy (served from docs/legal/)
GET /legal/terms-of-service No Terms of service
GET /legal/data-retention No Data retention policy
GET /legal/versions No Current versions of all legal documents