Skip to main content

Chrome Extension API Contract

Source of truth: docs/api/openapi.json (auto-generated) Regenerate: make openapi CI guard: make openapi-check (fails if spec is stale)
This document describes the API contract between chrome-shrine (TypeScript Chrome extension) and syntropy-journals (Python/FastAPI backend). Both teams must keep their implementations aligned with this contract. Repos:
  • Backend: Syntropy-Health/SyntropyJournal (this repo)
  • Extension: Syntropy-Health/chrome-shrine (see README.md > Backend API Contract)
  • Extension types: chrome-shrine/src/types/index.ts

Authentication

All extension endpoints (except /api/ext/api-key-exchange) require a Clerk JWT in the Authorization: Bearer <token> header. The extension obtains an sh_* API key via the exchange endpoint and uses it for subsequent requests.

Endpoints

Profile & Auth

MethodPathRequestResponseStatus
GET/api/ext/profileHealthProfileResponse200
POST/api/ext/api-key-exchangeClerkTokenExchange{ success, clerk_user_id, message }200

Food Logging

MethodPathRequestResponseStatus
POST/api/ext/food-logExtensionFoodLogRequestExtensionFoodLogResponse201

Diet Analysis

MethodPathRequestResponseStatus
POST/api/ext/diet/analyzeExtensionDietAnalysisRequestExtensionDietAnalysisResponse200
GET/api/ext/diet/score?days=7ExtensionDietScoreResponse200

Schema Mapping

HealthProfileResponseJournalHealthProfile

Backend (Python)Extension (TypeScript)Notes
dietary_preferences: dict[str, str]dietary_preferences: Record<string, any>TS is looser
supplement_stack: list[str]supplement_stack: string[]Aligned
health_goals: list[str]health_goals: string[]Aligned
conditions: list[str]conditions: string[]Aligned
allergies: list[str]allergies: string[]Aligned
metrics_data: dict[str, Any]metrics_data?: Record<string, any>TS optional, Python required (default {})

ExtensionFoodLogRequestJournalFoodLogRequest

Backend (Python)Extension (TypeScript)Notes
food_name: strfood_name: stringAligned
meal_type: Optional[str]meal_type?: 'breakfast'|'lunch'|'dinner'|'snack'|'supplement'TS has enum, Python is open string
calories: Optional[float]calories?: numberAligned
protein: Optional[float]protein?: numberAligned
carbs: Optional[float]carbs?: numberAligned
fat: Optional[float]fat?: numberAligned
source_url: Optional[str]source_url?: stringAligned (not persisted in DB yet)
notes: Optional[str]notes?: stringAligned

ExtensionFoodLogResponse ↔ Extension expectation

The extension checks response.success === true (boolean). Additional fields (food_log_id, food_name) are additive and ignored by the current client.

Error Responses

All endpoints return errors as:
{
  "detail": {
    "error": "ERROR_CODE",
    "message": "Human-readable message"
  }
}
Status codes: 400 (validation), 401 (auth), 500 (server error).

Versioning Policy

  • No breaking changes without a version bump in the URL prefix.
  • Additive fields (new optional response fields) are safe.
  • Removing or renaming fields requires a new version (/api/v2/ext/...).
  • The docs/api/openapi.json spec is the machine-readable contract.
  • CI enforces spec freshness via make openapi-check.

Keeping Contracts in Sync

  1. Backend changes: Run make openapi after modifying any API route or schema. Commit the updated docs/api/openapi.json. CI will block the PR if you forget.
  2. Extension changes: Before adding a new API call in chrome-shrine, check docs/api/openapi.json in the syntropy-journals repo to confirm the endpoint exists and the schema matches.
  3. New endpoints: Add the endpoint to the backend first, regenerate the spec, then implement the client in chrome-shrine.