{"openapi":"3.0.3","info":{"title":"NewsIntel API","version":"1.0.0","description":"Free-first personalized news briefing API. Multi-workspace via header x-workspace-id."},"servers":[{"url":"/"}],"tags":[{"name":"Health","description":"Service health and readiness checks"},{"name":"News","description":"News search and feed endpoints"},{"name":"Briefing","description":"Briefing generation and feedback"},{"name":"Profile","description":"User profile and sync management"},{"name":"Sources","description":"Source registry"},{"name":"Keys","description":"Dynamic API key management"},{"name":"OAuth","description":"X (Twitter) OAuth2 PKCE flow"},{"name":"Hooks","description":"Webhook-style trigger endpoints"},{"name":"Ops","description":"Operational status and diagnostics"},{"name":"Metrics","description":"Prometheus metrics exposition"},{"name":"Portal","description":"Web portal and static assets"},{"name":"Legal","description":"Legal pages (terms, privacy)"},{"name":"Docs","description":"API documentation"}],"paths":{"/healthz":{"get":{"tags":["Health"],"operationId":"getHealthz","summary":"Liveness health check","responses":{"200":{"description":"Service is alive","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["status","service","now"],"properties":{"status":{"type":"string","enum":["ok"]},"service":{"type":"string"},"now":{"type":"string","format":"date-time"}}}}}}}}}}},"/readyz":{"get":{"tags":["Health"],"operationId":"getReadyz","summary":"Readiness check for db/redis/queue dependencies","description":"Returns component-level detail when a bearer token is provided. Without auth, only aggregate status is returned.","responses":{"200":{"description":"All dependencies ready","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["status","timestamp"],"properties":{"status":{"type":"string","enum":["ready","not_ready"]},"mode":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"checks":{"type":"object","properties":{"db":{"$ref":"#/components/schemas/ComponentReadiness"},"redis":{"$ref":"#/components/schemas/ComponentReadiness"},"queue":{"$ref":"#/components/schemas/ComponentReadiness"}}}}}}}}}},"503":{"description":"One or more dependencies not ready","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/profile":{"get":{"tags":["Profile"],"operationId":"getProfile","summary":"Get normalized user profile","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"type":"object","required":["success","schema_version","workspace_id","profile"],"properties":{"success":{"type":"boolean","enum":[true]},"schema_version":{"type":"string"},"workspace_id":{"type":"string"},"profile":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/profile/sync":{"get":{"tags":["Profile"],"operationId":"listProfileSyncJobs","summary":"List recent profile sync jobs for current user","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"},{"name":"limit","in":"query","schema":{"type":"number","default":20},"description":"Max jobs to return"}],"responses":{"200":{"description":"Sync job list","content":{"application/json":{"schema":{"type":"object","required":["success","workspace_id","count","jobs"],"properties":{"success":{"type":"boolean","enum":[true]},"workspace_id":{"type":"string"},"count":{"type":"number"},"jobs":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}},"post":{"tags":["Profile"],"operationId":"syncProfile","summary":"Sync profile (manual/x-browser/x-api) and enqueue refresh job","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["manual","x-browser","x-api"]},"x_username":{"type":"string"},"free_text":{"type":"string"}}}}}},"responses":{"200":{"description":"Sync completed or queued","content":{"application/json":{"schema":{"type":"object","required":["success","accepted","workspace_id","sync_job_id"],"properties":{"success":{"type":"boolean","enum":[true]},"accepted":{"type":"boolean"},"workspace_id":{"type":"string"},"job_id":{"type":"string","nullable":true},"sync_job_id":{"type":"string"},"note":{"type":"string","nullable":true},"execution":{"type":"object","additionalProperties":true},"profile":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/profile/sync/{syncJobId}":{"get":{"tags":["Profile"],"operationId":"getProfileSyncJob","summary":"Get one profile sync job status","security":[{"bearerAuth":[]}],"parameters":[{"name":"syncJobId","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"Sync job detail","content":{"application/json":{"schema":{"type":"object","required":["success","workspace_id","job"],"properties":{"success":{"type":"boolean","enum":[true]},"workspace_id":{"type":"string"},"job":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"403":{"description":"Forbidden - job belongs to another user","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"404":{"description":"Sync job not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/sources":{"get":{"tags":["Sources"],"operationId":"listSources","summary":"List current source registry","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Source registry payload","content":{"application/json":{"schema":{"type":"object","required":["success","count","sources"],"properties":{"success":{"type":"boolean","enum":[true]},"count":{"type":"number"},"sources":{"type":"array","items":{"type":"object","required":["id","name","bias_label","reliability_score","enabled","tags"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"homepage_url":{"type":"string"},"rss_url":{"type":"string"},"country_code":{"type":"string"},"language":{"type":"string"},"bias_label":{"type":"string","enum":["left","center","right","unknown"]},"reliability_score":{"type":"number"},"enabled":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"}}},"additionalProperties":true}}},"additionalProperties":true}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/news/search":{"get":{"tags":["News"],"operationId":"searchNews","summary":"Search news with filters","description":"Main ranked feed endpoint supporting pagination, language, country, topic, and bias filters. Applies profile-aware ranking, trending boost, and story clustering.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"},{"name":"limit","in":"query","schema":{"type":"number","minimum":5,"maximum":50,"default":20},"description":"Items per page"},{"name":"page","in":"query","schema":{"type":"number","minimum":1,"default":1},"description":"Page number"},{"name":"country","in":"query","schema":{"type":"string"},"description":"Country code (e.g. BR, US)"},{"name":"topics","in":"query","schema":{"type":"string"},"description":"Comma-separated topic list"},{"name":"bias","in":"query","schema":{"type":"string"},"description":"Comma-separated bias labels"},{"name":"since_hours","in":"query","schema":{"type":"number"},"description":"Only items published within N hours"},{"name":"lang","in":"query","schema":{"type":"string"},"description":"Comma-separated language codes (e.g. pt,en)"}],"responses":{"200":{"description":"Paginated news items with ranking metadata","content":{"application/json":{"schema":{"type":"object","required":["success","items","pagination"],"properties":{"success":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"$ref":"#/components/schemas/NewsSearchItem"}},"pagination":{"type":"object","required":["page","limit","offset","has_more","count"],"properties":{"page":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"has_more":{"type":"boolean"},"count":{"type":"number"}}}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/briefing":{"get":{"tags":["Briefing"],"operationId":"getBriefing","summary":"Generate briefing payload/digest","description":"Applies source-quality gate (reliability_score >= BRIEFING_SOURCE_MIN_RELIABILITY) and bias-diversity gate for configured BRIEFING_BIAS_TARGETS (default: left/center/right). In strict mode (BRIEFING_BIAS_STRICT=true), unmet targets return degraded payload with explicit meta.stale_reason/meta.note and gate diagnostics in meta.gates.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"},{"name":"country","in":"query","schema":{"type":"string"}},{"name":"topics","in":"query","schema":{"type":"string"}},{"name":"bias","in":"query","schema":{"type":"string"}},{"name":"since_hours","in":"query","schema":{"type":"number"}},{"name":"limit","in":"query","schema":{"type":"number"}},{"name":"lang","in":"query","schema":{"type":"string"}},{"name":"for_agent","in":"query","schema":{"type":"string","enum":["1"]}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","digest"]}}],"responses":{"200":{"description":"Briefing payload","content":{"application/json":{"schema":{"type":"object","required":["success","schema_version","status","generated_at","cache_hit","meta","sections"],"properties":{"success":{"type":"boolean","enum":[true]},"schema_version":{"type":"string"},"status":{"type":"string","enum":["ok","degraded","stale"]},"generated_at":{"type":"string","format":"date-time"},"cache_hit":{"type":"boolean"},"digest_markdown":{"type":"string"},"agent_contract":{"type":"object","additionalProperties":true},"meta":{"type":"object","additionalProperties":true},"sections":{"type":"object","required":["breaking","local","world","topics"],"properties":{"breaking":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"local":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"world":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"topics":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}}}}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/briefing/agent":{"get":{"tags":["Briefing"],"operationId":"getBriefingAgent","summary":"Agent-optimized digest (Secretaria contract)","description":"Uses the same quality/diversity briefing gates as /briefing and exposes gate diagnostics in meta.gates/meta.note.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"Agent-ready briefing payload","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"sections":{"type":"object","properties":{"breaking":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"local":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"world":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}},"topics":{"type":"array","items":{"$ref":"#/components/schemas/NewsItemCard"}}}}}}]}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/briefing/feedback":{"post":{"tags":["Briefing"],"operationId":"postBriefingFeedback","summary":"Store user feedback for ranking loop","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["item_id","signal"],"additionalProperties":false,"properties":{"item_id":{"type":"string","minLength":1},"signal":{"type":"string","enum":["like","skip","save","irrelevant"]}}}}}},"responses":{"200":{"description":"Feedback persisted","content":{"application/json":{"schema":{"type":"object","required":["success","accepted"],"properties":{"success":{"type":"boolean","enum":[true]},"accepted":{"type":"boolean","enum":[true]}}}}}},"202":{"description":"Accepted with degraded async path","content":{"application/json":{"schema":{"type":"object","required":["success","accepted","note"],"properties":{"success":{"type":"boolean","enum":[true]},"accepted":{"type":"boolean","enum":[false]},"note":{"type":"string","enum":["db_unavailable"]}}}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/ops/status":{"get":{"tags":["Ops"],"operationId":"getOpsStatus","summary":"Operational status of db/redis/queue/providers","description":"Requires both bearer auth and x-ops-admin-key header.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"},{"name":"x-ops-admin-key","in":"header","required":true,"schema":{"type":"string"},"description":"Admin key for ops endpoints"}],"responses":{"200":{"description":"Operational status","content":{"application/json":{"schema":{"type":"object","required":["success","now","services"],"properties":{"success":{"type":"boolean","enum":[true]},"now":{"type":"string","format":"date-time"},"services":{"type":"object","properties":{"db":{"type":"string","enum":["up","down"]},"redis":{"type":"string","enum":["up","down"]},"queue":{"type":"string","enum":["up","down"]}}},"providers":{"type":"object","additionalProperties":true},"note":{"type":"string"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"403":{"description":"Forbidden - invalid or missing ops admin key","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/ops/feed-quality":{"get":{"tags":["Ops"],"operationId":"getOpsFeedQuality","summary":"Feed quality metrics for the current workspace","description":"Requires both bearer auth and x-ops-admin-key header.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"},{"name":"x-ops-admin-key","in":"header","required":true,"schema":{"type":"string"},"description":"Admin key for ops endpoints"}],"responses":{"200":{"description":"Feed quality snapshot","content":{"application/json":{"schema":{"type":"object","required":["success","workspace_id","quality"],"properties":{"success":{"type":"boolean","enum":[true]},"workspace_id":{"type":"string"},"quality":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"403":{"description":"Forbidden - invalid or missing ops admin key","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/keys":{"post":{"tags":["Keys"],"operationId":"createKey","summary":"Provision a new dynamic API key (plaintext shown only once)","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120}}}}}},"responses":{"201":{"description":"Key provisioned","content":{"application/json":{"schema":{"type":"object","required":["success","key","meta"],"properties":{"success":{"type":"boolean","enum":[true]},"key":{"type":"string","description":"Plaintext key (shown only once)"},"meta":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}},"get":{"tags":["Keys"],"operationId":"listKeys","summary":"List dynamic API key metadata for authenticated workspace/user","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"Metadata list (no plaintext secrets)","content":{"application/json":{"schema":{"type":"object","required":["success","count","keys"],"properties":{"success":{"type":"boolean","enum":[true]},"count":{"type":"number"},"keys":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/keys/{id}":{"delete":{"tags":["Keys"],"operationId":"deleteKey","summary":"Delete (revoke) one dynamic API key","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","required":["success","key"],"properties":{"success":{"type":"boolean","enum":[true]},"key":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"404":{"description":"Key not found or already revoked","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/keys/{id}/revoke":{"post":{"tags":["Keys"],"operationId":"revokeKey","summary":"Revoke one dynamic API key (deprecated, use DELETE /keys/{id})","deprecated":true,"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/workspaceId"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","required":["success","key"],"properties":{"success":{"type":"boolean","enum":[true]},"key":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"404":{"description":"Key not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/metrics":{"get":{"tags":["Metrics"],"operationId":"getMetrics","summary":"Prometheus metrics exposition for briefing and sync observability","description":"Open scrape endpoint exposing text/plain metrics in Prometheus format (version 0.0.4). Intended for internal/VPC scraping via network controls. Workspace label cardinality is bounded and over-limit values are collapsed to __overflow.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Prometheus text exposition","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/v1/hooks/trigger-sync":{"post":{"tags":["Hooks"],"operationId":"triggerSync","summary":"Trigger on-demand profile sync via async queue","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/workspaceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode"],"additionalProperties":false,"properties":{"mode":{"type":"string","enum":["manual","x-browser","x-api"]},"force":{"type":"boolean"},"reason":{"type":"string","minLength":1,"maxLength":500}}}}}},"responses":{"202":{"description":"Accepted for async processing","content":{"application/json":{"schema":{"type":"object","required":["success","accepted","workspace_id","sync_job_id","status"],"properties":{"success":{"type":"boolean","enum":[true]},"accepted":{"type":"boolean","enum":[true]},"workspace_id":{"type":"string"},"sync_job_id":{"type":"string"},"job_id":{"type":"string","nullable":true},"status":{"type":"string","enum":["queued"]},"note":{"type":"string","nullable":true,"enum":["queue_disabled_test_mode","queue_unavailable"]}}}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"401":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/oauth/x/start":{"post":{"tags":["OAuth"],"operationId":"startOAuthX","summary":"Public self-serve start for X OAuth2 PKCE (no bearer bootstrap required)","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"redirect_uri":{"type":"string"},"workspace_id":{"type":"string"}}}}}},"responses":{"200":{"description":"OAuth flow started","content":{"application/json":{"schema":{"type":"object","required":["success","provider","authorize_url","state"],"properties":{"success":{"type":"boolean","enum":[true]},"provider":{"type":"string","enum":["x"]},"authorize_url":{"type":"string","format":"uri"},"state":{"type":"string"}}}}}},"400":{"description":"Missing redirect URI","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"429":{"description":"Rate limited"},"503":{"description":"OAuth client not configured","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}}}}},"/oauth/x/callback":{"get":{"tags":["OAuth"],"operationId":"callbackOAuthX","summary":"Handle X callback, derive stable identity, rotate/provision API key and show plaintext once in success page","parameters":[{"name":"state","in":"query","required":true,"schema":{"type":"string"}},{"name":"code","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"HTML success page with plaintext key (shown once)","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Missing/invalid/expired/replayed state or missing code","content":{"text/html":{"schema":{"type":"string"}}}},"429":{"description":"Rate limited"},"502":{"description":"Provider exchange/userinfo failure","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/oauth/x/poll":{"get":{"tags":["OAuth"],"operationId":"pollOAuthX","summary":"Poll for OAuth result (CLI auth flow). Returns pending/completed/error status with API key on completion.","parameters":[{"name":"state","in":"query","required":true,"schema":{"type":"string","minLength":10,"maxLength":500}}],"responses":{"200":{"description":"Poll result","content":{"application/json":{"schema":{"type":"object","required":["success","status"],"properties":{"success":{"type":"boolean"},"status":{"type":"string","enum":["pending","completed","error"]},"api_key":{"type":"string","description":"Provisioned API key (only when status=completed)"},"username":{"type":"string","description":"X username (only when status=completed)"},"workspace_id":{"type":"string","description":"Workspace ID (only when status=completed)"},"error":{"type":"string","description":"Error message (only when status=error)"}}}}}},"400":{"description":"Invalid or missing state parameter","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}}}},"429":{"description":"Rate limited"}}}},"/portal":{"get":{"tags":["Portal"],"operationId":"getPortal","summary":"Web portal dashboard (HTML)","responses":{"200":{"description":"Portal HTML page","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/portal.js":{"get":{"tags":["Portal"],"operationId":"getPortalJs","summary":"Portal client-side JavaScript bundle","responses":{"200":{"description":"JavaScript file","content":{"application/javascript":{"schema":{"type":"string"}}}}}}},"/favicon.ico":{"get":{"tags":["Portal"],"operationId":"getFavicon","summary":"Favicon (empty 204)","responses":{"204":{"description":"No content"}}}},"/docs":{"get":{"tags":["Docs"],"operationId":"getDocs","summary":"Interactive API documentation page (HTML)","responses":{"200":{"description":"Documentation HTML page","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/legal/terms":{"get":{"tags":["Legal"],"operationId":"getLegalTerms","summary":"Terms of service page (HTML)","responses":{"200":{"description":"Terms of service HTML","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/legal/privacy":{"get":{"tags":["Legal"],"operationId":"getLegalPrivacy","summary":"Privacy policy page (HTML)","responses":{"200":{"description":"Privacy policy HTML","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"tags":["Legal"],"operationId":"redirectTerms","summary":"Redirect to /legal/terms","responses":{"302":{"description":"Redirect to /legal/terms"}}}},"/privacy":{"get":{"tags":["Legal"],"operationId":"redirectPrivacy","summary":"Redirect to /legal/privacy","responses":{"302":{"description":"Redirect to /legal/privacy"}}}}},"components":{"schemas":{"NewsItemCard":{"type":"object","required":["id","title","summary","url","source_id","source_name","country_code","bias_label","reliability_score","topics","section","published_at","fetched_at","relevance_score","image_url","thumbnail_url","focus_score"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"url":{"type":"string"},"source_id":{"type":"string"},"source_name":{"type":"string"},"country_code":{"type":"string"},"bias_label":{"type":"string","enum":["left","center","right","unknown"]},"reliability_score":{"type":"number"},"topics":{"type":"array","items":{"type":"string"}},"section":{"type":"string","enum":["breaking","local","world","topic"]},"published_at":{"type":"string","format":"date-time"},"fetched_at":{"type":"string","format":"date-time"},"relevance_score":{"type":"number"},"image_url":{"type":"string","nullable":true},"thumbnail_url":{"type":"string","nullable":true},"focus_score":{"type":"number","minimum":0,"maximum":1},"language":{"type":"string"}}},"NewsSearchItem":{"type":"object","description":"Simplified news item returned by /news/search","properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"source":{"type":"string"},"published_at":{"type":"string","format":"date-time"},"image_url":{"type":"string","nullable":true},"summary":{"type":"string","nullable":true},"topics":{"type":"array","items":{"type":"string"}},"country":{"type":"string","nullable":true},"language":{"type":"string","nullable":true}}},"ComponentReadiness":{"type":"object","required":["status","latency_ms"],"properties":{"status":{"type":"string","enum":["up","down","skipped"]},"latency_ms":{"type":"number"},"detail":{"type":"string"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"API key obtained via OAuth flow or /keys endpoint"}},"parameters":{"workspaceId":{"name":"x-workspace-id","in":"header","required":false,"schema":{"type":"string"},"description":"Workspace/Tenant identifier (ex.: secretaria)"}}}}