{"openapi":"3.1.0","info":{"title":"MESSAI API","version":"2026-10-07","description":"Read access to the MESSAI corpus of microbial electrochemical systems\nresearch.\n\n- **/api/v1** is the public API: paper search, paper detail, the parameter\n  catalog and API key management, under the stability contract below.\n- **Unversioned endpoints** (/api/research/search, /api/papers/{id},\n  /api/ml/predict, /api/parameters/{slug}/hierarchical-prior, /api/chat) serve\n  the MESSAI website and can change with it.\n\n## Authentication\n\n/api/v1 works without credentials. An API key puts your calls on their own\nquota: create one at https://www.messai.io/profile and send it as\n`X-API-Key: sk_free_…` (or `Authorization: Bearer sk_free_…`). A key\nis shown once, when it is created; MESSAI stores only its SHA-256 hash. A\nrevoked or expired key gets 401 — it never falls back to anonymous access.\nManaging keys (/api/v1/api-keys) needs a signed-in www.messai.io session.\n\nThe unversioned endpoints take no credentials. A signed-in browser session\nchanges two of them: POST /api/chat offers larger models and POST\n/api/ml/predict stores the prediction against your account.\n\n## Rate limits\n\nEvery request draws tokens from a token bucket kept per caller and shared\nwith the website. Buckets refill continuously.\n\n| Caller | Budget | Bucket key |\n| --- | --- | --- |\n| API key (/api/v1) | 1,000 requests/day: one more every 86.4 s, up to 1,000 at once | account (all of an account's keys share it) |\n| Anonymous | 60 tokens/min, burst 120 | IP address (IPv6 grouped to its /64) |\n| Signed-in browser session | 300 tokens/min, burst 600 | account |\n\nA GET or HEAD costs 1 token. POST\n/api/ml/predict costs 10, POST /api/chat 25, and other writes 2. Each operation below\nlists its cost as `x-ratelimit-cost`.\n\n/api/v1 responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and\n`X-RateLimit-Reset` (seconds until the next token); the other endpoints carry\n`RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`. Over budget\nthe API answers 429 with `Retry-After`. If the limiter's store is\nunreachable, cheap requests go through and expensive ones get 503\n`rate_limiter_unavailable`.\n\n## Stability (/api/v1)\n\n- Within v1, changes are additive only: new endpoints, new optional\n  parameters, new response fields. Ignore fields you do not know.\n- Removing or renaming a field or parameter, or changing what it means, ships\n  as /api/v2. v1 keeps answering for at least six months after v2 is\n  announced on https://www.messai.io/api-docs.\n- Unknown query parameters are rejected with 400, so a typo never widens a\n  query silently.\n- Errors are `{ \"data\": null, \"error\": { \"code\", \"message\" } }`. Branch on\n  `code`; `message` is for people and may change.\n\nRequest schemas below are generated from the handlers' own validation.\nHuman-readable guide: https://www.messai.io/api-docs","contact":{"name":"MESSAI","url":"https://www.messai.io/collaborate"}},"servers":[{"url":"https://www.messai.io","description":"Production"}],"tags":[{"name":"v1","description":"The public, versioned API"},{"name":"Papers","description":"Search and read the research corpus"},{"name":"Parameters","description":"Parameter priors fitted on the corpus"},{"name":"Prediction","description":"Reactor performance prediction"},{"name":"Chat","description":"Corpus-grounded AI chat"}],"paths":{"/api/v1/papers":{"get":{"operationId":"v1ListPapers","summary":"Search and browse papers","description":"With `q`: hybrid keyword + embedding search for `sort=relevance` (top 200 keyword and top 200 embedding matches, so `total` counts that candidate set), keyword matching for the other sorts. Without `q`: the corpus in the /research order. Only papers that pass the corpus visibility rules are listed, so every listed id resolves at /api/v1/papers/{id}.","tags":["v1"],"security":[{},{"ApiKeyAuth":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Free-text query. Omit to browse the corpus.","schema":{"type":"string","maxLength":500}},{"name":"systemType","in":"query","required":false,"description":"One of the 17 primary system types (MFC, MEC, MES, MDC, …), case-insensitive. Papers the classifier has not labelled never match.","schema":{"type":"string","enum":["MFC","MEC","MES","MDC","MSC","MEFS","MESNORK","MERC","MNRC","MMRC","MRB","MBES","MREC","MCDI","REVIEW","FUNDAMENTAL","OTHER"]}},{"name":"yearStart","in":"query","required":false,"description":"Earliest publication year, inclusive.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"yearEnd","in":"query","required":false,"description":"Latest publication year, inclusive.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"sort","in":"query","required":false,"description":"relevance: best match first (with q), else the /research default order. date: newest first. citations: most cited first.","schema":{"default":"relevance","type":"string","enum":["relevance","date","citations"]}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"description":"Papers per page.","schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Papers","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"type":"object","properties":{"papers":{"type":"array","items":{"$ref":"#/components/schemas/V1Paper"}},"pagination":{"$ref":"#/components/schemas/V1Pagination"},"searchType":{"type":"string","enum":["browse","hybrid","keyword"]},"degraded":{"type":"boolean","description":"Present when the embedding service was down and hybrid fell back to keyword."}}},"error":{"type":"null"}}}}}},"400":{"description":"`invalid_request`: an unknown parameter or an invalid value","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"401":{"description":"`invalid_api_key`, `api_key_revoked` or `api_key_expired`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"429":{"description":"Over budget (`rate_limited`), or the limiter is unreachable on a write","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"503":{"description":"`api_keys_unavailable`: keyed calls before keys are enabled","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":1}},"/api/v1/papers/{id}":{"get":{"operationId":"v1GetPaper","summary":"One paper","description":"An id that names a merged duplicate returns the surviving paper with `redirectedFrom`. Hidden papers, placeholder records and archived rows answer 404.","tags":["v1"],"security":[{},{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"200":{"description":"Paper","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"$ref":"#/components/schemas/V1PaperDetail"},"error":{"type":"null"}}}}}},"400":{"description":"`invalid_request`: malformed id","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"401":{"description":"`invalid_api_key`, `api_key_revoked` or `api_key_expired`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"404":{"description":"`not_found`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"429":{"description":"Over budget (`rate_limited`), or the limiter is unreachable on a write","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":1}},"/api/v1/parameters":{"get":{"operationId":"v1ListParameters","summary":"The parameter catalog","description":"Parameter definitions: canonical slug, name, unit, category. Ordered by curation priority, then category, then name. The slug is what /api/parameters/{slug}/… endpoints take.","tags":["v1"],"security":[{},{"ApiKeyAuth":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Matches the slug, name or description, e.g. \"coulombic efficiency\".","schema":{"type":"string","maxLength":100}},{"name":"category","in":"query","required":false,"description":"Parameter category, case-insensitive.","schema":{"type":"string","enum":["ENVIRONMENTAL","BIOLOGICAL","ELECTROCHEMICAL","MATERIALS","OPERATIONAL","PERFORMANCE","REACTOR_DESIGN","SUBSTRATE_MEDIA","CHEMICAL","PHYSICAL","MONITORING_CONTROL","ECONOMIC","SAFETY_REGULATORY","GAS_MANAGEMENT","SYSTEM_RESILIENCE","APPLICATION_SPECIFIC","EMERGING_TECHNOLOGY","INTEGRATION_SCALING"]}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":1000}},{"name":"limit","in":"query","required":false,"description":"Parameters per page.","schema":{"default":50,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Parameters","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"type":"object","properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/V1Parameter"}},"pagination":{"$ref":"#/components/schemas/V1Pagination"}}},"error":{"type":"null"}}}}}},"400":{"description":"`invalid_request`: an unknown parameter or an invalid value","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"401":{"description":"`invalid_api_key`, `api_key_revoked` or `api_key_expired`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"429":{"description":"Over budget (`rate_limited`), or the limiter is unreachable on a write","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":1}},"/api/v1/api-keys":{"get":{"operationId":"v1ListApiKeys","summary":"List your API keys","description":"Newest first. Never returns a key or its hash.","tags":["v1"],"security":[{"SessionCookie":[]}],"responses":{"200":{"description":"Keys","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyView"}}}},"error":{"type":"null"}}}}}},"401":{"description":"`unauthorized`: no signed-in session","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"503":{"description":"`api_keys_unavailable`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":1},"post":{"operationId":"v1CreateApiKey","summary":"Create an API key","description":"The response is the only time the key is shown. Up to 10 active keys per account; they share the account's 1,000 requests/day.","tags":["v1"],"security":[{"SessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"A label to tell your keys apart."},"expiresInDays":{"description":"Days until the key stops working. Omit or null for no expiry.","anyOf":[{"type":"integer","minimum":1,"maximum":365},{"type":"null"}]}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"The key, shown once","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"type":"object","properties":{"key":{"type":"string","pattern":"^sk_[a-z]+_[0-9a-f]{64}$"},"apiKey":{"$ref":"#/components/schemas/ApiKeyView"}}},"error":{"type":"null"}}}}}},"400":{"description":"`invalid_request`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"401":{"description":"`unauthorized`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"409":{"description":"`key_limit_reached`: revoke a key first","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"503":{"description":"`api_keys_unavailable`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":2}},"/api/v1/api-keys/{id}":{"delete":{"operationId":"v1RevokeApiKey","summary":"Revoke an API key","description":"The key stops working at once. Revoking twice is harmless.","tags":["v1"],"security":[{"SessionCookie":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The revoked key","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","error"],"properties":{"data":{"type":"object","properties":{"apiKey":{"$ref":"#/components/schemas/ApiKeyView"}}},"error":{"type":"null"}}}}}},"401":{"description":"`unauthorized`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"404":{"description":"`not_found`: no such key on your account","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}},"503":{"description":"`api_keys_unavailable`","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Error"}}}}},"x-ratelimit-cost":2}},"/api/research/search":{"get":{"operationId":"searchCorpus","summary":"Search the research corpus","description":"Keyword, semantic or hybrid (default) search over the corpus. With no `q` the endpoint browses: papers that pass the visibility rules first, then the rest of the real papers the classifier set aside. Text queries rank the top 200 keyword matches (and, in hybrid mode, the top 200 embedding matches), so `totalCount` counts that candidate set. Edge-cached for 30 s.","tags":["Papers"],"parameters":[{"name":"q","in":"query","description":"Free-text query (alias: `query`). Empty = browse.","schema":{"type":"string","maxLength":500}},{"name":"searchType","in":"query","schema":{"type":"string","enum":["keyword","semantic","hybrid"],"default":"hybrid"}},{"name":"page","in":"query","description":"Zero-based page index.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"filters","in":"query","description":"JSON object, URL-encoded. `primarySystemType` takes the 17-type taxonomy (MFC, MEC, MES, …); `systemType` filters the older free-text classification.","content":{"application/json":{"schema":{"type":"object","properties":{"systemType":{"type":"array","items":{"type":"string"}},"yearRange":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}}},"minCitations":{"type":"number"},"minConfidence":{"type":"number","minimum":0,"maximum":1},"hasMetrics":{"type":"boolean"},"hasExtractedParams":{"type":"boolean"},"needsExtraction":{"type":"boolean"},"journals":{"type":"array","items":{"type":"string"}},"paperType":{"anyOf":[{"type":"string","enum":["EXPERIMENTAL","REVIEW","META_ANALYSIS","MODELING","PERSPECTIVE","OTHER"]},{"type":"array","items":{"type":"string","enum":["EXPERIMENTAL","REVIEW","META_ANALYSIS","MODELING","PERSPECTIVE","OTHER"]}}]},"minComprehensiveness":{"type":"number","minimum":0,"maximum":100},"primarySystemType":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"studyFocus":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"applicationDomain":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}}}}},{"name":"sort","in":"query","description":"JSON object, URL-encoded, e.g. {\"field\":\"citations\",\"order\":\"desc\"}. Hybrid and semantic results stay in relevance order.","content":{"application/json":{"schema":{"type":"object","properties":{"field":{"default":"relevance","type":"string","enum":["relevance","date","citations","confidence","quality"]},"order":{"default":"desc","type":"string","enum":["asc","desc"]}}}}}},{"name":"includeStats","in":"query","schema":{"type":"boolean","default":false}},{"name":"includeSuggestions","in":"query","schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"papers":{"type":"array","items":{"$ref":"#/components/schemas/SearchPaper"}},"totalCount":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"totalPages":{"type":"integer"},"searchType":{"type":"string"},"degraded":{"type":"boolean","description":"Present when the embedding service was down and hybrid fell back to keyword ranking."}},"additionalProperties":true}},"additionalProperties":true}}}},"400":{"description":"Invalid query parameters (`error.details` lists the issues)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"object","properties":{"message":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true}}}},"429":{"description":"Over budget. `Retry-After` gives the wait in seconds.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","rate_limiter_unavailable"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds until enough tokens have refilled."}},"additionalProperties":true}}}},"503":{"description":"Semantic mode only: the embedding service is unreachable","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}}},"x-ratelimit-cost":1}},"/api/papers/{id}":{"get":{"operationId":"getPaper","summary":"Get one paper record","description":"The stored ResearchPaper record by id. An id that names a merged duplicate returns the surviving paper plus `redirectedFrom`.","tags":["Papers"],"parameters":[{"name":"id","in":"path","required":true,"description":"Paper id (a CUID such as \"cmabc123…\")","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"Paper record","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"abstract":{"type":["string","null"]},"doi":{"type":["string","null"]},"journal":{"type":["string","null"]},"publicationDate":{"type":["string","null"],"format":"date-time"},"primarySystemType":{"type":["string","null"]}},"additionalProperties":true,"description":"The full ResearchPaper record"},"error":{"type":"null"},"redirectedFrom":{"type":"string"}},"additionalProperties":true}}}},"404":{"description":"No paper with this id","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"null"},"error":{"type":"object","properties":{"message":{"type":"string"},"code":{"const":"NOT_FOUND"}},"additionalProperties":true}},"additionalProperties":true}}}},"429":{"description":"Over budget. `Retry-After` gives the wait in seconds.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","rate_limiter_unavailable"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds until enough tokens have refilled."}},"additionalProperties":true}}}}},"x-ratelimit-cost":1}},"/api/ml/predict":{"post":{"operationId":"predictPerformance","summary":"Predict reactor performance","description":"Runs the shared prediction orchestrator for one reactor configuration and returns the multi-block response (powerOutput, efficiency, voltage, currentDensity, empirical_context, epistemic.ood, calibration, hierarchical_priors, …). Every block reports its own `data_status` instead of zero-filling. Hybrid mode: `?hybrid=true` or the `x-use-hybrid: true` header.","tags":["Prediction"],"parameters":[{"name":"hybrid","in":"query","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"systemType":{"type":"string","minLength":1},"materials":{"type":"object","properties":{"anodeMaterial":{"type":"string"},"cathodeMaterial":{"type":"string"},"membraneType":{"type":["string","null"]},"anodeSurfaceArea":{"type":"number"},"cathodeSurfaceArea":{"type":"number"}},"required":["anodeMaterial","cathodeMaterial","anodeSurfaceArea","cathodeSurfaceArea"]},"conditions":{"type":"object","properties":{"temperature":{"type":"number"},"ph":{"type":"number"},"pressure":{"type":"number"},"substrateConcentration":{"type":"number"},"externalResistance":{"type":"number"},"substrateId":{"type":"string"},"codMgL":{"type":"number"},"hrtHours":{"type":"number"},"biofilmThicknessMm":{"type":"number"},"appliedVoltage":{"type":"number"}},"required":["temperature","ph","pressure"]},"organism":{"type":"object","properties":{"id":{"type":"string"}}},"configuration":{"type":"object","properties":{"reactorVolume":{"type":"number"},"electrodeSpacing":{"type":"number"},"numChambers":{"type":"number"}},"required":["reactorVolume","electrodeSpacing","numChambers"]},"optimization":{"type":"object","properties":{"target":{"type":"string","enum":["power","efficiency","cost","durability"]},"constraints":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}}},"required":["target"]}},"required":["systemType","materials","conditions","configuration"]}}}},"responses":{"200":{"description":"Prediction blocks","content":{"application/json":{"schema":{"type":"object","properties":{"predictionId":{"type":["string","null"],"description":"Set for a signed-in caller; null when anonymous."}},"additionalProperties":true}}}},"400":{"description":"The body does not match the request schema","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"additionalProperties":true}}},"additionalProperties":true}}}},"429":{"description":"Over budget. `Retry-After` gives the wait in seconds.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","rate_limiter_unavailable"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds until enough tokens have refilled."}},"additionalProperties":true}}}},"500":{"description":"Prediction failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"additionalProperties":true}}}}},"x-ratelimit-cost":10}},"/api/parameters/{slug}/hierarchical-prior":{"get":{"operationId":"getHierarchicalPrior","summary":"A parameter's hierarchical Bayesian prior","description":"The v1 PyMC NUTS fit for a canonical parameter slug: a pooled stratum and one per system type, each with MCMC diagnostics, after the same serving gate /api/ml/predict applies. Branch on `data_status`. ISR-cached for 60 s.","tags":["Parameters"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Canonical parameter slug, e.g. \"power_density\"","schema":{"type":"string"}},{"name":"version","in":"query","description":"Pin a prior artifact version; unknown values answer `unknown_version`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Prior (check `data_status`)","content":{"application/json":{"schema":{"type":"object","properties":{"parameter":{"type":"string"},"data_status":{"type":"string","enum":["populated","awaiting_artifact","parameter_not_in_priors","unresolved_parent","unknown_version"]},"pooled":{"$ref":"#/components/schemas/PriorStratum"},"by_system_type":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/PriorStratum"}},"_source":{"type":"string","enum":["db","json","unavailable"]}},"additionalProperties":true}}}},"429":{"description":"Over budget. `Retry-After` gives the wait in seconds.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","rate_limiter_unavailable"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds until enough tokens have refilled."}},"additionalProperties":true}}}},"500":{"description":"The prior artifact exists but could not be read","content":{"application/json":{"schema":{"type":"object","properties":{"data_status":{"const":"read_error"}},"additionalProperties":true}}}}},"x-ratelimit-cost":1}},"/api/chat":{"post":{"operationId":"chat","summary":"Citation-grounded research chat","description":"Streams an answer from the corpus-grounded assistant (AI SDK UI message stream over text/event-stream). The assistant calls corpus, prior and predictor tools and cites the papers it used. Larger models need a signed-in session.","tags":["Chat"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","description":"The conversation so far, oldest first.","minItems":1,"maxItems":30,"items":{"oneOf":[{"type":"object","properties":{"role":{"type":"string","const":"user"},"content":{"type":"string","maxLength":8000}},"required":["role","content"]},{"type":"object","properties":{"role":{"type":"string","const":"assistant"},"content":{"type":"string","maxLength":64000}},"required":["role","content"]}]}},"mode":{"type":"string","enum":["general","lab-design"],"default":"general"},"model":{"type":"string","description":"Model id; omit for the default."},"locale":{"type":"string","enum":["en","de"]}},"additionalProperties":true,"required":["messages"]}}}},"responses":{"200":{"description":"Event stream of the answer","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"additionalProperties":true}}}},"429":{"description":"Over budget. `Retry-After` gives the wait in seconds.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","rate_limiter_unavailable"]},"message":{"type":"string"},"retryAfter":{"type":"integer","description":"Seconds until enough tokens have refilled."}},"additionalProperties":true}}}}},"x-ratelimit-cost":25}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Optional on /api/v1. Create a key at https://www.messai.io/profile. `Authorization: Bearer sk_…` is accepted too."},"SessionCookie":{"type":"apiKey","in":"cookie","name":"__Secure-next-auth.session-token","description":"A signed-in www.messai.io browser session; needed to manage API keys."}},"schemas":{"SearchPaper":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"authors":{"type":"array","items":{}},"abstract":{"type":"string"},"publicationDate":{"type":["string","null"],"format":"date-time"},"journal":{"type":["string","null"]},"doi":{"type":["string","null"]},"url":{"type":["string","null"]},"systemType":{"type":["string","null"],"description":"Older free-text classification"},"primarySystemType":{"type":["string","null"],"description":"17-type taxonomy (MFC, MEC, MES, …)"},"paperType":{"type":["string","null"]},"citationCount":{"type":["integer","null"]},"relevanceScore":{"type":"number"}},"additionalProperties":true},"PriorStratum":{"type":"object","properties":{"n_papers":{"type":"integer"},"n_obs":{"type":"integer"},"scale":{"type":"string","enum":["log","linear"]},"unit":{"type":["string","null"]},"mu":{"type":"number"},"median":{"type":"number"},"ci95_low":{"type":"number"},"ci95_high":{"type":"number"},"mu_log":{"type":"number"},"tau_log":{"type":"number"},"sigma_within_log":{"type":"number"},"rhat_max":{"type":"number"},"ess_bulk_min":{"type":"number"},"n_divergences":{"type":"integer"},"converged":{"type":"boolean"}},"additionalProperties":true},"V1Error":{"type":"object","required":["data","error"],"properties":{"data":{"type":"null"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable identifier to branch on."},"message":{"type":"string"},"details":{"description":"Validation issues, when there are any."}}}}},"V1Pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"pages":{"type":"integer"}}},"V1Paper":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"authors":{"type":"array","items":{"type":"string"}},"abstract":{"type":["string","null"]},"year":{"type":["integer","null"]},"journal":{"type":["string","null"]},"doi":{"type":["string","null"]},"url":{"type":["string","null"]},"systemType":{"type":["string","null"],"enum":["MFC","MEC","MES","MDC","MSC","MEFS","MESNORK","MERC","MNRC","MMRC","MRB","MBES","MREC","MCDI","REVIEW","FUNDAMENTAL","OTHER",null],"description":"The 17-type taxonomy class; null when the classifier has not labelled the paper."},"paperType":{"type":["string","null"]},"citationCount":{"type":["integer","null"]},"relevanceScore":{"type":"number","description":"Only with `q`."}}},"V1PaperDetail":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"authors":{"type":"array","items":{"type":"string"}},"abstract":{"type":["string","null"]},"year":{"type":["integer","null"]},"journal":{"type":["string","null"]},"doi":{"type":["string","null"]},"url":{"type":["string","null"]},"systemType":{"type":["string","null"],"enum":["MFC","MEC","MES","MDC","MSC","MEFS","MESNORK","MERC","MNRC","MMRC","MRB","MBES","MREC","MCDI","REVIEW","FUNDAMENTAL","OTHER",null],"description":"The 17-type taxonomy class; null when the classifier has not labelled the paper."},"paperType":{"type":["string","null"]},"citationCount":{"type":["integer","null"]},"pubmedId":{"type":["string","null"]},"arxivId":{"type":["string","null"]},"keywords":{"type":"array","items":{"type":"string"}},"applicationDomains":{"type":"array","items":{"type":"string"}},"aiSummary":{"type":["string","null"],"description":"Machine-generated summary of the abstract, not the authors' words."},"redirectedFrom":{"type":"string","description":"Set when the requested id was a merged duplicate of this paper."}}},"V1Parameter":{"type":"object","properties":{"slug":{"type":["string","null"],"description":"Null on definitions not yet curated."},"name":{"type":"string"},"unit":{"type":["string","null"]},"category":{"type":"string","enum":["ENVIRONMENTAL","BIOLOGICAL","ELECTROCHEMICAL","MATERIALS","OPERATIONAL","PERFORMANCE","REACTOR_DESIGN","SUBSTRATE_MEDIA","CHEMICAL","PHYSICAL","MONITORING_CONTROL","ECONOMIC","SAFETY_REGULATORY","GAS_MANAGEMENT","SYSTEM_RESILIENCE","APPLICATION_SPECIFIC","EMERGING_TECHNOLOGY","INTEGRATION_SCALING"]},"description":{"type":["string","null"]}}},"ApiKeyView":{"type":"object","description":"A key as its owner sees it: never the key, never its hash.","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","description":"The first characters, e.g. sk_free_1a2b3c4d."},"tier":{"type":"string","enum":["free"]},"status":{"type":"string","enum":["active","revoked","expired"]},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time","description":"Kept to the minute."},"expiresAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}}}},"headers":{"XRateLimitLimit":{"description":"Size of the bucket this call drew on (1000 for an API key).","schema":{"type":"integer"}},"XRateLimitRemaining":{"description":"Tokens left in the bucket after this call.","schema":{"type":"integer"}},"XRateLimitReset":{"description":"Seconds until the next token is added.","schema":{"type":"integer"}},"RetryAfter":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}}}