{"openapi":"3.1.0","info":{"title":"MentionsAPI","version":"0.1.0","description":"One API for ChatGPT, Claude, Gemini, and Perplexity. Query all four in parallel, get structured brand mentions and deduplicated citations back. See the full docs at https://mentionsapi.com/docs.","contact":{"name":"MentionsAPI Support","email":"hello@mentionsapi.com","url":"https://mentionsapi.com/docs"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.mentionsapi.com","description":"Production"}],"tags":[{"name":"Ask","description":"Multi-provider LLM queries with brand + citation extraction."},{"name":"Keys","description":"API key management (dashboard-authenticated)."},{"name":"Billing","description":"Credit top-ups and Stripe customer portal."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"lvk_(live|test)_…","description":"Server-generated API key issued via the dashboard or POST /v1/keys. Send as `Authorization: Bearer lvk_live_…`."},"SupabaseJWT":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Supabase session JWT (the logged-in dashboard user). Used only by account-management endpoints (`/v1/keys`, `/v1/stripe/*`). NOT the same as an API key."}},"schemas":{"AskRequest":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"maxLength":10000},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string","minLength":1,"maxLength":20000}},"required":["role","content"]},"minItems":1,"maxItems":50},"system_message":{"type":"string","minLength":1,"maxLength":20000},"providers":{"type":"array","items":{"type":"string","enum":["openai","anthropic","gemini","perplexity"]},"minItems":1,"maxItems":4},"model":{"type":"object","properties":{"openai":{"type":"string","minLength":1,"maxLength":100},"anthropic":{"type":"string","minLength":1,"maxLength":100},"gemini":{"type":"string","minLength":1,"maxLength":100},"perplexity":{"type":"string","minLength":1,"maxLength":100}}},"params":{"type":"object","properties":{"temperature":{"type":"number","minimum":0,"maximum":2},"max_tokens":{"type":"integer","minimum":1,"maximum":8000}}},"json_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64},"schema":{"type":"object","additionalProperties":{}},"strict":{"type":"boolean"}},"required":["name","schema"]},"cache_scope":{"type":"string","enum":["shared","private"],"default":"shared"},"track_brands":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":10},"web_search":{"type":"boolean","default":true},"country":{"type":"string","minLength":2,"maxLength":2},"async":{"type":"boolean"},"webhook_id":{"type":"string","format":"uuid"},"mode":{"type":"string","enum":["live","standard"],"default":"live"}}},"ProviderId":{"type":"string","enum":["openai","anthropic","gemini","perplexity"]},"Citation":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"title":{"type":"string"},"snippet":{"type":"string"}},"required":["url"]},"ProviderResult":{"type":"object","properties":{"provider":{"$ref":"#/components/schemas/ProviderId"},"model":{"type":"string","example":"gpt-4o-2024-08-06"},"content":{"type":"string"},"citations":{"type":"array","items":{"$ref":"#/components/schemas/Citation"}},"tokens":{"type":"object","properties":{"input":{"type":"integer"},"output":{"type":"integer"},"reasoning":{"type":"integer"}},"required":["input","output"]},"latency_ms":{"type":"integer"}},"required":["provider","model","content","citations","tokens","latency_ms"]},"ProviderError":{"type":"object","properties":{"provider":{"$ref":"#/components/schemas/ProviderId"},"error":{"type":"object","properties":{"code":{"type":"string","example":"provider_timeout"},"message":{"type":"string"}},"required":["code","message"]}},"required":["provider","error"]},"BrandMention":{"type":"object","properties":{"brand":{"type":"string"},"provider":{"$ref":"#/components/schemas/ProviderId"},"rank":{"type":"integer","minimum":1,"description":"1-indexed position of the first mention inside the provider response."},"sentiment":{"type":"string","enum":["positive","neutral","negative"]},"context":{"type":"string"}},"required":["brand","provider","rank","sentiment","context"]},"AggregatedCitation":{"type":"object","properties":{"canonical_url":{"type":"string","format":"uri"},"domains":{"type":"array","items":{"type":"string"}},"providers_cited":{"type":"array","items":{"$ref":"#/components/schemas/ProviderId"}},"title":{"type":"string"}},"required":["canonical_url","domains","providers_cited"]},"AskResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"id":{"type":"string","format":"uuid"},"cached":{"type":"boolean"},"cache_tier":{"type":"string","enum":["l1","l2","l3","miss"]},"providers":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/ProviderResult"},{"$ref":"#/components/schemas/ProviderError"}]}},"brand_mentions":{"type":"array","items":{"$ref":"#/components/schemas/BrandMention"}},"citations":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedCitation"}},"usage":{"type":"object","properties":{"billable_units":{"type":"integer"},"latency_ms":{"type":"integer"},"cost_cents":{"type":"integer"}},"required":["billable_units","latency_ms"]}},"required":["request_id","id","cached","cache_tier","providers","brand_mentions","citations","usage"]},"ErrorObject":{"type":"object","properties":{"code":{"type":"string","example":"insufficient_credits"},"message":{"type":"string","example":"This call costs 5¢ but your balance is only 2¢. Top up at https://mentionsapi.com/app/billing."},"balance_cents":{"type":"integer"},"required_cents":{"type":"integer"}},"required":["code","message"]},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"request_id":{"type":"string","format":"uuid"}},"required":["error"]},"KeyCreateRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"mode":{"type":"string","enum":["live","test"],"default":"live"}},"required":["name"]},"KeyListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string","example":"lvk_live_ab"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["active","revoked"]},"created_at":{"type":"string","format":"date-time"},"last_used_at":{"type":["string","null"],"format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time"}},"required":["id","name","prefix","mode","status","created_at","last_used_at","revoked_at"]},"KeyListResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"keys":{"type":"array","items":{"$ref":"#/components/schemas/KeyListItem"}}},"required":["request_id","keys"]},"KeyCreateResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"key":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["active","revoked"]},"created_at":{"type":"string","format":"date-time"},"token":{"type":"string","description":"Plaintext API key. Returned ONCE at creation. Store it securely.","example":"lvk_live_abc123…"}},"required":["id","name","prefix","mode","status","created_at","token"]}},"required":["request_id","key"]},"KeyRevokeResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"revoked":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["request_id","revoked","id"]},"TopupRequest":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1000,"maximum":100000,"description":"Credit amount in cents. Min 1000 ($10), max 100000 ($1000)."},"success_url":{"type":"string","format":"uri"},"cancel_url":{"type":"string","format":"uri"}},"required":["amount_cents"]},"TopupResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri","description":"Stripe Checkout URL. Redirect the user here to complete payment."},"amount_cents":{"type":"integer"}},"required":["request_id","url","amount_cents"]},"PortalRequest":{"type":"object","properties":{"return_url":{"type":"string","format":"uri"}}},"PortalResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri","description":"Stripe Billing Portal URL. Redirect the user here to manage payment methods."}},"required":["request_id","url"]}},"parameters":{}},"paths":{"/v1/ask":{"post":{"tags":["Ask"],"summary":"Multi-provider LLM query with optional brand + citation extraction","description":"Fans out a single prompt to ChatGPT, Claude, Gemini, and Perplexity (or a subset), deduplicates citations, extracts brand mentions, and returns one normalized payload. Cache tiers (l1/l2/l3) are automatic; the `cache_scope` parameter controls whether the response can be shared across accounts.","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"maxLength":10000},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string","minLength":1,"maxLength":20000}},"required":["role","content"]},"minItems":1,"maxItems":50},"system_message":{"type":"string","minLength":1,"maxLength":20000},"providers":{"type":"array","items":{"type":"string","enum":["openai","anthropic","gemini","perplexity"]},"minItems":1,"maxItems":4},"model":{"type":"object","properties":{"openai":{"type":"string","minLength":1,"maxLength":100},"anthropic":{"type":"string","minLength":1,"maxLength":100},"gemini":{"type":"string","minLength":1,"maxLength":100},"perplexity":{"type":"string","minLength":1,"maxLength":100}}},"params":{"type":"object","properties":{"temperature":{"type":"number","minimum":0,"maximum":2},"max_tokens":{"type":"integer","minimum":1,"maximum":8000}}},"json_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64},"schema":{"type":"object","additionalProperties":{}},"strict":{"type":"boolean"}},"required":["name","schema"]},"cache_scope":{"type":"string","enum":["shared","private"],"default":"shared"},"track_brands":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":10},"web_search":{"type":"boolean","default":true},"country":{"type":"string","minLength":2,"maxLength":2},"async":{"type":"boolean"},"webhook_id":{"type":"string","format":"uuid"},"mode":{"type":"string","enum":["live","standard"],"default":"live"}}}}}},"responses":{"200":{"description":"Successful response — at least one provider returned content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskResponse"}}}},"401":{"description":"Missing, malformed, or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Insufficient credits to fulfill the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/keys":{"get":{"tags":["Keys"],"summary":"List API keys for the authenticated account","description":"Dashboard-only. Auth is a Supabase JWT (the logged-in user) — NOT an API key. Returns keys newest-first; plaintext tokens are never returned (they were shown once at creation).","security":[{"SupabaseJWT":[]}],"responses":{"200":{"description":"Array of keys belonging to the account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyListResponse"}}}},"401":{"description":"Missing or invalid session JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Keys"],"summary":"Create a new API key","description":"Mints a `lvk_live_…` or `lvk_test_…` token. The plaintext `token` in the response is only returned on this call — store it immediately.","security":[{"SupabaseJWT":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyCreateRequest"}}}},"responses":{"201":{"description":"Key created. Plaintext token returned ONCE.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyCreateResponse"}}}},"401":{"description":"Missing or invalid session JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/keys/{id}":{"delete":{"tags":["Keys"],"summary":"Revoke an API key","description":"Marks the key as `revoked` and purges the 60-second APIKEY_KV cache so revocation takes effect on the next request.","security":[{"SupabaseJWT":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Key revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyRevokeResponse"}}}},"401":{"description":"Missing or invalid session JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Key not found, or does not belong to the calling account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/stripe/topup":{"post":{"tags":["Billing"],"summary":"Create a Stripe Checkout Session for a credit top-up","description":"Returns a one-time Stripe Checkout URL. Credits are granted automatically on `checkout.session.completed` (with a `payment_intent.succeeded` fallback). Credits never expire.","security":[{"SupabaseJWT":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupRequest"}}}},"responses":{"200":{"description":"Checkout Session created. Redirect the user to `url`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupResponse"}}}},"400":{"description":"Invalid request (e.g. amount below $10 or above $1,000).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid session JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/stripe/portal":{"post":{"tags":["Billing"],"summary":"Create a Stripe Billing Portal link","description":"Returns a short-lived URL to the Stripe Customer Portal so the user can manage payment methods and download receipts. Requires the account to have at least one prior top-up (i.e. a Stripe customer already exists).","security":[{"SupabaseJWT":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalRequest"}}}},"responses":{"200":{"description":"Portal session created. Redirect the user to `url`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalResponse"}}}},"400":{"description":"Account has no associated Stripe customer yet. Top up credits first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid session JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"webhooks":{}}