{"openapi":"3.1.0","info":{"title":"LANGR API","version":"4.0.0","description":"Unified API gateway for cross-project services: mail, SMS, auth, payment, SEO, content generation, and i18n translation.\n\nAll authenticated endpoints require a Bearer API key in the Authorization header:\n```\nAuthorization: Bearer lk_live_xxx\n```","contact":{"name":"LANGR","email":"hikmet@langr.dk","url":"https://langr.org"},"license":{"name":"MIT"}},"servers":[{"url":"https://api.langr.org","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key starting with `lk_live_`"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}},"tags":[{"name":"Health","description":"Service health checks"},{"name":"Mail","description":"Transactional email + the LANGR Mail multi-account API: connect Gmail/IMAP mailboxes and read, send and manage them all through one API."},{"name":"SMS","description":"Send SMS messages and OTP codes"},{"name":"Auth","description":"Authentication: OTP, magic links, Google OAuth, sessions"},{"name":"Payment","description":"Stripe checkout, billing portal, webhooks"},{"name":"SEO","description":"SEO pipeline: audits, keywords, rankings, backlinks"},{"name":"Content","description":"AI content generation via Claude"},{"name":"i18n","description":"Translation service with 120+ locales"},{"name":"Keys","description":"API key management (admin)"},{"name":"Billing","description":"Tier pricing, usage tracking, and upgrades"},{"name":"Developers","description":"Self-service developer signup and account management"},{"name":"Brain","description":"AI Intelligence Layer: smart query resolution, knowledge graph, domain scanning, feedback loop"}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Public health check","security":[],"responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"version":{"type":"string"},"uptime":{"type":"integer"}}}}}}}}},"/v1/health":{"get":{"tags":["Health"],"summary":"Authenticated health check with backend status","responses":{"200":{"description":"Detailed health with backend connectivity","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"version":{"type":"string"},"uptime":{"type":"integer"},"services":{"type":"object","additionalProperties":{"type":"object","properties":{"ok":{"type":"boolean"},"latency":{"type":"integer"},"error":{"type":"string"}}}}}}}}}}}},"/v1/mail/send":{"post":{"tags":["Mail"],"summary":"Send email","description":"Send an email via Resend. Requires `mail:send` scope.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","to","subject"],"properties":{"from":{"type":"string","example":"noreply@langr.org"},"to":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"},"reply_to":{"type":"string"},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Email sent","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string"}}}}}},"400":{"$ref":"#/components/schemas/Error"}}}},"/v1/mail/inbox/{namespace}":{"get":{"tags":["Mail"],"summary":"Read inbox messages","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Inbox messages"}}}},"/v1/mail/message/{key}":{"get":{"tags":["Mail"],"summary":"Read single email message","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full email message"}}}},"/v1/mail/domains":{"get":{"tags":["Mail"],"summary":"List available email domains","responses":{"200":{"description":"Domain list"}}}},"/v1/sms/send":{"post":{"tags":["SMS"],"summary":"Send SMS message","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","message"],"properties":{"to":{"type":"string","example":"+4527141448"},"message":{"type":"string"},"sender":{"type":"string"}}}}}},"responses":{"200":{"description":"SMS sent"}}}},"/v1/sms/send-otp":{"post":{"tags":["SMS"],"summary":"Send OTP code via SMS","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to"],"properties":{"to":{"type":"string"}}}}}},"responses":{"200":{"description":"OTP sent (code not returned)"}}}},"/v1/sms/verify-otp":{"post":{"tags":["SMS"],"summary":"Verify SMS OTP code","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","code"],"properties":{"to":{"type":"string"},"code":{"type":"string"}}}}}},"responses":{"200":{"description":"Verification result"}}}},"/v1/sms/stats":{"get":{"tags":["SMS"],"summary":"SMS delivery statistics","responses":{"200":{"description":"SMS stats"}}}},"/v1/auth/send-otp":{"post":{"tags":["Auth"],"summary":"Send OTP (auto-detect email/SMS)","description":"Auto-detects whether target is email or phone number and sends OTP via appropriate channel.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target"],"properties":{"target":{"type":"string","description":"Email address or phone number","example":"user@example.com"}}}}}},"responses":{"200":{"description":"OTP sent","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channel":{"type":"string","enum":["email","sms"]}}}}}}}}},"/v1/auth/verify-otp":{"post":{"tags":["Auth"],"summary":"Verify OTP and get session token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target","code"],"properties":{"target":{"type":"string"},"code":{"type":"string","minLength":6,"maxLength":6}}}}}},"responses":{"200":{"description":"Session token","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"session_token":{"type":"string","description":"Starts with `las_`, 30-day TTL"},"expires_at":{"type":"string","format":"date-time"}}}}}}}}},"/v1/auth/magic-link":{"post":{"tags":["Auth"],"summary":"Send magic link email","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","redirect_url"],"properties":{"email":{"type":"string","format":"email"},"redirect_url":{"type":"string","format":"uri"},"subject":{"type":"string"}}}}}},"responses":{"200":{"description":"Magic link sent"}}}},"/v1/auth/magic-link/verify":{"post":{"tags":["Auth"],"summary":"Verify magic link token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Token starting with `lml_`"}}}}}},"responses":{"200":{"description":"Session token"}}}},"/v1/auth/google/authorize":{"post":{"tags":["Auth"],"summary":"Get Google OAuth authorization URL","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect_url"],"properties":{"redirect_url":{"type":"string","format":"uri"},"scopes":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"OAuth URL","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"url":{"type":"string"},"state":{"type":"string"}}}}}}}}},"/v1/auth/google/callback":{"get":{"tags":["Auth"],"summary":"Google OAuth callback (browser redirect)","security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to project with session token"}}},"post":{"tags":["Auth"],"summary":"Google OAuth code exchange (API)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"Session token + user info"}}}},"/v1/auth/session/validate":{"post":{"tags":["Auth"],"summary":"Validate session token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token"],"properties":{"session_token":{"type":"string"}}}}}},"responses":{"200":{"description":"Session validity"}}}},"/v1/auth/sessions":{"get":{"tags":["Auth"],"summary":"List active sessions","responses":{"200":{"description":"Session list"}}},"delete":{"tags":["Auth"],"summary":"Revoke all sessions","responses":{"200":{"description":"All sessions revoked"}}}},"/v1/auth/session/{id}":{"delete":{"tags":["Auth"],"summary":"Revoke specific session","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session revoked"}}}},"/v1/payment/checkout":{"post":{"tags":["Payment"],"summary":"Create Stripe checkout session","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["success_url","cancel_url"],"properties":{"mode":{"type":"string","enum":["payment","subscription"],"default":"payment"},"line_items":{"type":"array","items":{"type":"object"}},"lookup_key":{"type":"string"},"success_url":{"type":"string","format":"uri"},"cancel_url":{"type":"string","format":"uri"},"customer_email":{"type":"string","format":"email"},"customer_id":{"type":"string"},"metadata":{"type":"object"},"trial_period_days":{"type":"integer","minimum":1,"maximum":90},"locale":{"type":"string"},"account":{"type":"string","enum":["langr","aya"],"default":"langr"}}}}}},"responses":{"200":{"description":"Checkout session","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"session_id":{"type":"string"},"url":{"type":"string"}}}}}}}}},"/v1/payment/portal":{"post":{"tags":["Payment"],"summary":"Create Stripe billing portal session","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customer_id","return_url"],"properties":{"customer_id":{"type":"string"},"return_url":{"type":"string","format":"uri"},"account":{"type":"string","enum":["langr","aya"]}}}}}},"responses":{"200":{"description":"Portal session URL"}}}},"/v1/payment/webhook":{"post":{"tags":["Payment"],"summary":"Stripe webhook (signature verified)","security":[],"responses":{"200":{"description":"Webhook processed"}}}},"/v1/payment/events":{"get":{"tags":["Payment"],"summary":"List payment events","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}},{"name":"type","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Payment events"}}}},"/v1/seo/audit":{"post":{"tags":["SEO"],"summary":"Trigger domain audit","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","example":"langr.org"},"callback_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Audit triggered"}}}},"/v1/seo/audit/{id}":{"get":{"tags":["SEO"],"summary":"Get audit results","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Audit data"}}}},"/v1/seo/projects":{"get":{"tags":["SEO"],"summary":"List pipeline projects","responses":{"200":{"description":"Project list"}}}},"/v1/seo/keywords/{projectId}":{"get":{"tags":["SEO"],"summary":"Keyword tracking data","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Keywords"}}}},"/v1/seo/rankings/{projectId}":{"get":{"tags":["SEO"],"summary":"Position tracking","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Rankings"}}}},"/v1/seo/backlinks/{projectId}":{"get":{"tags":["SEO"],"summary":"Backlink profile","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backlinks"}}}},"/v1/seo/competitors/{projectId}":{"get":{"tags":["SEO"],"summary":"Competitor analysis","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Competitors"}}}},"/v1/seo/analyst/{projectId}":{"get":{"tags":["SEO"],"summary":"AI analysis report","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"AI report"}}}},"/v1/seo/lighthouse":{"post":{"tags":["SEO"],"summary":"Run Lighthouse performance scan","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"viewports":{"type":"array","items":{"type":"string","enum":["mobile","tablet","desktop"]}}}}}}},"responses":{"200":{"description":"Lighthouse results"}}}},"/v1/seo/bootstrap":{"post":{"tags":["SEO"],"summary":"Bootstrap new project","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Project bootstrapped"}}}},"/v1/seo/pipeline/trigger":{"post":{"tags":["SEO"],"summary":"Trigger pipeline run","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["projectId"],"properties":{"projectId":{"type":"string"},"modules":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Pipeline triggered"}}}},"/v1/seo/health":{"get":{"tags":["SEO"],"summary":"VPS pipeline health","responses":{"200":{"description":"Pipeline health"}}}},"/v1/content/generate":{"post":{"tags":["Content"],"summary":"Generate AI content","description":"Generate content using Claude Haiku. Supports 7 content types with locale and context control.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"type":{"type":"string","enum":["blog_post","seo_copy","product_description","email","social","newsletter","custom"],"default":"custom"},"prompt":{"type":"string","maxLength":10000},"context":{"type":"object","properties":{"domain":{"type":"string"},"keywords":{"type":"array","items":{"type":"string"}},"tone":{"type":"string"},"audience":{"type":"string"},"brand":{"type":"string"}}},"locale":{"type":"string","default":"en"},"max_tokens":{"type":"integer","default":4096,"minimum":100,"maximum":8192},"temperature":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"Generated content","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"content":{"type":"string"},"type":{"type":"string"},"locale":{"type":"string"},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}},"model":{"type":"string"}}}}}}}}},"/v1/content/usage":{"get":{"tags":["Content"],"summary":"Content generation usage stats","description":"Returns 30-day usage data per project.","responses":{"200":{"description":"Usage data","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"project_id":{"type":"string"},"period":{"type":"string"},"total_requests":{"type":"integer"},"total_tokens":{"type":"integer"},"daily":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"requests":{"type":"integer"},"tokens":{"type":"integer"}}}}}}}}}}}},"/v1/i18n/translate":{"post":{"tags":["i18n"],"summary":"Translate text to multiple locales","description":"Translate a string or JSON object to up to 50 target locales using Claude Haiku. RTL-aware.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_locales"],"properties":{"text":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":{"type":"string"}}],"description":"String or JSON object to translate"},"source_locale":{"type":"string","default":"en"},"target_locales":{"type":"array","items":{"type":"string"},"maxItems":50},"context":{"type":"string","description":"Context for better translation accuracy"},"formal":{"type":"boolean","description":"Use formal register"}}}}}},"responses":{"200":{"description":"Translations","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"translations":{"type":"object","description":"Locale code → translated text/object"},"rtl_locales":{"type":"array","items":{"type":"string"}},"usage":{"type":"object"},"model":{"type":"string"}}}}}}}}},"/v1/i18n/locales":{"get":{"tags":["i18n"],"summary":"List supported locales","description":"Returns 120+ locales with native names, RTL flags, and fallback chains.","parameters":[{"name":"rtl","in":"query","schema":{"type":"boolean"},"description":"Filter RTL locales only"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by code or name"}],"responses":{"200":{"description":"Locale list","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"locales":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"rtl":{"type":"boolean"},"fallback":{"type":"string","nullable":true},"fallback_chain":{"type":"array","items":{"type":"string"}}}}},"total":{"type":"integer"},"rtl_count":{"type":"integer"}}}}}}}}},"/v1/billing/tiers":{"get":{"tags":["Billing"],"summary":"List available tiers","description":"Returns all billing tiers with pricing and limits. No authentication required.","security":[],"responses":{"200":{"description":"Tier list","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tiers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"daily_limit":{"oneOf":[{"type":"integer"},{"type":"string"}]},"rpm":{"type":"integer"},"price_monthly_eur":{"type":"number"},"price_annual_eur":{"type":"number"}}}}}}}}}}}},"/v1/billing/usage":{"get":{"tags":["Billing"],"summary":"Get current usage","description":"Returns daily usage stats for the authenticated API key.","responses":{"200":{"description":"Usage data","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tier":{"type":"string"},"daily_limit":{"oneOf":[{"type":"integer"},{"type":"string"}]},"daily_used":{"type":"integer"},"daily_remaining":{"oneOf":[{"type":"integer"},{"type":"string"}]},"rpm":{"type":"integer"}}}}}}}}},"/v1/billing/upgrade":{"post":{"tags":["Billing"],"summary":"Upgrade tier","description":"Creates a Stripe checkout session for upgrading to Pro tier.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tier","success_url","cancel_url"],"properties":{"tier":{"type":"string","enum":["pro"]},"interval":{"type":"string","enum":["monthly","annual"],"default":"monthly"},"success_url":{"type":"string","format":"uri"},"cancel_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Checkout session","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"session_id":{"type":"string"},"url":{"type":"string","format":"uri"}}}}}}}}},"/v1/developers/signup":{"post":{"tags":["Developers"],"summary":"Create developer account","description":"Self-service signup. Creates a Free tier API key. No authentication required.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","minLength":1},"project_name":{"type":"string"}}}}}},"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"message":{"type":"string"},"api_key":{"type":"string","description":"Shown only once"},"key_prefix":{"type":"string"},"tier":{"type":"string"},"daily_limit":{"type":"integer"},"scopes":{"type":"array","items":{"type":"string"}}}}}}},"409":{"description":"Email already exists"}}}},"/v1/developers/me":{"get":{"tags":["Developers"],"summary":"Get developer account","description":"Returns account info for the authenticated API key.","responses":{"200":{"description":"Account info","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"account":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"},"tier":{"type":"string"},"daily_limit":{"oneOf":[{"type":"integer"},{"type":"string"}]},"rpm":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}}}}}}}}}},"/v1/keys":{"get":{"tags":["Keys"],"summary":"List API keys","responses":{"200":{"description":"Key list (hashes not included)"}}},"post":{"tags":["Keys"],"summary":"Create API key","description":"Creates a new API key. The raw key is returned only once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","owner_id","scopes"],"properties":{"name":{"type":"string"},"owner_type":{"type":"string","enum":["project","user","service"]},"owner_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"role":{"type":"string"},"rate_limit_rpm":{"type":"integer"},"environment":{"type":"string","enum":["live","test"]}}}}}},"responses":{"200":{"description":"New API key (shown only once)"}}}},"/v1/keys/{id}":{"patch":{"tags":["Keys"],"summary":"Update API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"rate_limit_rpm":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated key"}}},"delete":{"tags":["Keys"],"summary":"Revoke API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked"}}}},"/v1/keys/{id}/rotate":{"post":{"tags":["Keys"],"summary":"Rotate API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"New key (old revoked)"}}}},"/v1/brain/query":{"post":{"tags":["Brain"],"summary":"Ask Brain anything","description":"Smart Router: 4-step resolution cascade (Redis cache → DB cache → knowledge graph → Claude fallback). Responses are cached and knowledge is extracted for future queries.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1,"maxLength":10000,"description":"The question to ask"},"context":{"type":"object","description":"Additional context key-value pairs"},"domain":{"type":"string","description":"Domain context for the query"},"model":{"type":"string","description":"Claude model override (default: haiku)"},"max_tokens":{"type":"integer","minimum":100,"maximum":8192,"description":"Max response tokens"}}}}}},"responses":{"200":{"description":"Brain response with resolution metadata","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"answer":{"type":"string"},"resolution":{"type":"string","enum":["redis_cache","db_cache","knowledge_match","claude_generated"]},"confidence":{"type":"number"},"cache_id":{"type":"string"},"knowledge_ids":{"type":"array","items":{"type":"string"}},"tokens":{"type":"object","properties":{"input":{"type":"integer"},"output":{"type":"integer"}}},"cost_usd":{"type":"number"},"latency_ms":{"type":"integer"},"model":{"type":"string"}}}}}},"400":{"$ref":"#/components/schemas/Error"},"502":{"description":"AI/external service error"}}}},"/v1/brain/domain":{"post":{"tags":["Brain"],"summary":"Scan a domain","description":"Scan a domain for industry, tech stack, SEO signals. Uses 24h stale-while-revalidate caching.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain to scan (e.g. example.com)"},"force":{"type":"boolean","description":"Force fresh scan (skip cache)"}}}}}},"responses":{"200":{"description":"Domain profile with scan results"},"502":{"description":"VPS scan error"}}}},"/v1/brain/domain/{domain}":{"get":{"tags":["Brain"],"summary":"Get cached domain profile","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cached domain profile"},"404":{"description":"No profile found for domain"}}}},"/v1/brain/store":{"post":{"tags":["Brain"],"summary":"Store knowledge item","description":"Store a knowledge item with deduplication via SHA-256 content hash. Supports 8 categories and superseding chains.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["category","subject","content"],"properties":{"category":{"type":"string","enum":["fact","rule","convention","preference","correction","domain_signal","feature_pattern","industry_pattern"]},"subject":{"type":"string","maxLength":500},"content":{"type":"string","maxLength":50000},"tags":{"type":"array","items":{"type":"string"},"maxItems":20},"confidence":{"type":"number","minimum":0,"maximum":1},"supersedes":{"type":"string","format":"uuid","description":"ID of knowledge item this supersedes"},"source":{"type":"string"},"source_ref":{"type":"string"}}}}}},"responses":{"200":{"description":"Stored knowledge item"},"400":{"$ref":"#/components/schemas/Error"}}}},"/v1/brain/knowledge":{"get":{"tags":["Brain"],"summary":"Search knowledge graph","description":"Search tenant-isolated knowledge with optional global sharing. Supports category, tag, and confidence filters.","parameters":[{"name":"query","in":"query","schema":{"type":"string"},"description":"Text search query"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filter by category"},{"name":"tags","in":"query","schema":{"type":"string"},"description":"Comma-separated tags"},{"name":"min_confidence","in":"query","schema":{"type":"number"},"description":"Minimum confidence threshold"},{"name":"limit","in":"query","schema":{"type":"integer"},"description":"Max results (1-100)"},{"name":"include_global","in":"query","schema":{"type":"boolean"},"description":"Include global knowledge (default: true)"}],"responses":{"200":{"description":"Knowledge items matching search criteria"}}}},"/v1/brain/knowledge/{id}":{"get":{"tags":["Brain"],"summary":"Get knowledge item by ID","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Knowledge item"},"404":{"description":"Not found"}}},"delete":{"tags":["Brain"],"summary":"Deactivate knowledge item","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Item deactivated"},"404":{"description":"Not found"}}}},"/v1/brain/feedback":{"post":{"tags":["Brain"],"summary":"Submit feedback on a response","description":"Thumbs up (+1) boosts confidence by 0.05, thumbs down (-1) reduces by 0.15. Corrections become new knowledge items at 0.9 confidence.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rating"],"properties":{"cache_id":{"type":"string","format":"uuid","description":"ID of the cached response"},"query_text":{"type":"string","description":"Original query text"},"rating":{"type":"integer","enum":[-1,1],"description":"1 = thumbs up, -1 = thumbs down"},"correction":{"type":"string","description":"Corrected answer (creates new knowledge at 0.9 confidence)"}}}}}},"responses":{"200":{"description":"Feedback recorded"},"400":{"$ref":"#/components/schemas/Error"}}}},"/v1/brain/stats":{"get":{"tags":["Brain"],"summary":"Brain usage statistics","description":"Daily query counts, cache hit rates, knowledge graph size, and network effects metrics.","responses":{"200":{"description":"Brain stats","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"stats":{"type":"object","properties":{"queries_today":{"type":"integer"},"cache_hits_today":{"type":"integer"},"claude_calls_today":{"type":"integer"},"cache_hit_rate":{"type":"number"},"knowledge_items":{"type":"integer"},"domain_profiles":{"type":"integer"}}}}}}}}}}},"/v1/brain/ingest":{"post":{"tags":["Brain"],"summary":"Trigger ingestion pipeline","description":"Admin-only: ingest data from 6 source systems (matrix, products, features, capabilities, projects, cross-matrix) into the unified knowledge graph. Idempotent via ingestion log.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"string","enum":["matrix","products","features","capabilities","projects","cross-matrix"]},"description":"Specific sources to ingest (default: all)"}}}}}},"responses":{"200":{"description":"Ingestion results per source"},"403":{"description":"Requires brain:admin scope"}}}},"/v1/mail/accounts":{"get":{"tags":["Mail"],"summary":"List connected mail accounts","description":"List the signed-in user's connected external mailboxes (Gmail, IMAP, …). Requires `mail:accounts` scope and the user's `session_token` (query or body).","security":[{"bearerAuth":[]}],"parameters":[{"name":"session_token","in":"query","required":true,"schema":{"type":"string"},"description":"User session token (las_…)"}],"responses":{"200":{"description":"Accounts list","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"email":{"type":"string"}}}}}}}}}}}},"/v1/mail/accounts/all":{"get":{"tags":["Mail"],"summary":"Unified inbox across all accounts","description":"The unified LANGR Mail call: returns messages from ALL of the user's connected mailboxes, merged and sorted by date, each tagged with its account. Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"maximum":50}}],"responses":{"200":{"description":"Merged inbox","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"accounts":{"type":"array","items":{"type":"object"}},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"fromName":{"type":"string"},"fromEmail":{"type":"string"},"subject":{"type":"string"},"date":{"type":"string"},"preview":{"type":"string"},"account":{"type":"object"}}}}}}}}}}}},"/v1/mail/accounts/google/authorize":{"post":{"tags":["Mail"],"summary":"Connect a Gmail account (OAuth)","description":"Start the 'Connect Gmail' OAuth flow. Returns a Google consent URL; after consent Google redirects to the callback which stores a refresh token for the user. Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","redirect_url"],"properties":{"session_token":{"type":"string"},"redirect_url":{"type":"string","example":"https://app.langr.org/mail"}}}}}},"responses":{"200":{"description":"Consent URL","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"url":{"type":"string"}}}}}}}}},"/v1/mail/accounts/imap":{"post":{"tags":["Mail"],"summary":"Connect any mailbox via IMAP","description":"Connect any provider (iCloud, Outlook, Yahoo, work mail, Gmail-via-app-password) with email + app password. Host/port auto-detected for known providers; override with the optional fields. Credentials are verified before saving. Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","email","password"],"properties":{"session_token":{"type":"string"},"email":{"type":"string"},"password":{"type":"string","description":"App password (not the normal login password)"},"imap_host":{"type":"string"},"imap_port":{"type":"integer"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer"}}}}}},"responses":{"200":{"description":"Connected","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"email":{"type":"string"}}}}}},"400":{"description":"IMAP authentication failed"}}}},"/v1/mail/accounts/{id}":{"delete":{"tags":["Mail"],"summary":"Disconnect a mail account","description":"Disconnect (revoke) one of the user's connected mailboxes. Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Disconnected"}}}},"/v1/mail/accounts/{id}/messages":{"get":{"tags":["Mail"],"summary":"List one account's inbox","description":"List recent inbox messages for one connected account (provider-dispatched: Gmail API or IMAP). Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"maximum":50}}],"responses":{"200":{"description":"Inbox"}}}},"/v1/mail/accounts/{id}/message":{"get":{"tags":["Mail"],"summary":"Read one message","description":"Fetch a full message (body + headers) from one account. `mid` is the provider message id (Gmail id or IMAP UID). Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"mid","in":"query","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Message"}}}},"/v1/mail/accounts/{id}/send":{"post":{"tags":["Mail"],"summary":"Send from one account","description":"Send a message from a connected account (Gmail API or IMAP/SMTP). Requires `mail:accounts` scope + `session_token`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","to","subject","text"],"properties":{"session_token":{"type":"string"},"to":{"type":"string"},"subject":{"type":"string"},"text":{"type":"string"}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sent"}}}},"/v1/mail/accounts/microsoft/authorize":{"post":{"tags":["Mail"],"summary":"Connect an Outlook/Microsoft 365 account (OAuth)","description":"Start the Microsoft OAuth flow (Microsoft Graph mail). Returns a consent URL; the callback stores a refresh token. Requires `mail:accounts` scope + `session_token`. Needs MICROSOFT_CLIENT_ID/SECRET (Azure app) configured server-side.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","redirect_url"],"properties":{"session_token":{"type":"string"},"redirect_url":{"type":"string","example":"https://app.langr.org/mail"}}}}}},"responses":{"200":{"description":"Consent URL"},"503":{"description":"Microsoft not configured"}}}},"/v1/mail/accounts/{id}/messages/{mid}/action":{"post":{"tags":["Mail"],"summary":"Message action (read/star/archive/trash)","description":"Perform an action on a message in a connected account: read, unread, star, unstar, archive, trash. Dispatched per provider (Gmail/IMAP/Outlook). Requires mail:accounts + session_token.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"mid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","action"],"properties":{"session_token":{"type":"string"},"action":{"type":"string","enum":["read","unread","star","unstar","archive","trash"]}}}}}},"responses":{"200":{"description":"Done"}}}},"/v1/mail/accounts/{id}/search":{"get":{"tags":["Mail"],"summary":"Search one account inbox","description":"Search a connected account inbox by free text (subject/from/body). Requires mail:accounts + session_token.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"q","in":"query","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Results"}}}},"/v1/mail/accounts/{id}/folders":{"get":{"tags":["Mail"],"summary":"List folders/labels","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folders"}}},"post":{"tags":["Mail"],"summary":"Create folder/label","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","name"],"properties":{"session_token":{"type":"string"},"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Created"}}}},"/v1/mail/accounts/{id}/folder-messages":{"get":{"tags":["Mail"],"summary":"List messages in a folder","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"folder","in":"query","required":true,"schema":{"type":"string"}},{"name":"session_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Messages"}}}},"/v1/mail/accounts/{id}/messages/{mid}/move":{"post":{"tags":["Mail"],"summary":"Move message to a folder","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"mid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_token","folder"],"properties":{"session_token":{"type":"string"},"folder":{"type":"string"}}}}}},"responses":{"200":{"description":"Moved"}}}}}}