{"openapi":"3.0.0","info":{"title":"fitbit-metrics","version":"1.0.0","description":"Cloudflare Worker exposing Fitbit health data as Prometheus metrics"},"security":[{"Bearer":[]}],"components":{"securitySchemes":{"Bearer":{"type":"http","scheme":"bearer","description":"Token returned from the /callback endpoint after OAuth authorization"}},"schemas":{},"parameters":{}},"paths":{"/authorize":{"get":{"tags":["Auth"],"summary":"Start Fitbit OAuth2 flow","description":"Redirects to Fitbit's authorization page. No authentication required.","responses":{"302":{"description":"Redirect to Fitbit OAuth2 authorization"}}}},"/callback":{"get":{"tags":["Auth"],"summary":"OAuth2 callback","description":"Handles the Fitbit OAuth2 callback. Returns an API token on success.","parameters":[{"schema":{"type":"string","description":"Authorization code from Fitbit","example":"abc123"},"required":true,"description":"Authorization code from Fitbit","name":"code","in":"query"},{"schema":{"type":"string","description":"CSRF state token","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"description":"CSRF state token","name":"state","in":"query"}],"responses":{"200":{"description":"Authorization successful, returns your API token","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"message":{"type":"string"}},"required":["token","message"]}}}},"400":{"description":"Missing query parameters"},"403":{"description":"Invalid or expired OAuth state"},"502":{"description":"Fitbit token exchange failed"}}}},"/metrics":{"get":{"tags":["Metrics"],"summary":"Prometheus scrape endpoint","description":"Returns Fitbit health data formatted as Prometheus metrics. Requires bearer token. By default returns the most recent 30 days; pass ?daysAgo to shift the 30-day window further into the past (e.g. 30, 60, 90) to backfill historical data.","security":[{"Bearer":[]}],"parameters":[{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Shift the 30-day window this many days into the past. 0 (default) = most recent 30 days; 30 = the 30 days before that; 60, 90, … reach further back. Windows with daysAgo>0 are immutable and cached for longer.","example":0},"required":false,"description":"Shift the 30-day window this many days into the past. 0 (default) = most recent 30 days; 30 = the 30 days before that; 60, 90, … reach further back. Windows with daysAgo>0 are immutable and cached for longer.","name":"daysAgo","in":"query"}],"responses":{"200":{"description":"Prometheus-formatted metrics","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"Invalid query parameter (daysAgo must be a non-negative integer)"},"401":{"description":"Unauthorized"},"500":{"description":"Error fetching metrics"}}}},"/purge":{"get":{"tags":["Cache"],"summary":"Purge cached Fitbit API responses","description":"Deletes all cached API responses for the authenticated user. Requires bearer token.","security":[{"Bearer":[]}],"responses":{"200":{"description":"Cache purged","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"}}}},"/":{"get":{"tags":["Info"],"summary":"Landing page","responses":{"200":{"description":"HTML landing page","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"tags":["Info"],"summary":"LLM-friendly plain text description","responses":{"200":{"description":"Plain text README for LLMs","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"tags":["Info"],"summary":"Health check","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}}}}