{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"MetaPhrase Developer API","version":"1.0.0","summary":"Six writing tools. One consistent API.","description":"API keys: https://metaphrase.msalman.com/dashboard. Full AI-ready Markdown: https://metaphrase.msalman.com/llms-full.txt. Standard defaults: 20,000 Unicode code points, 15 requests/minute and 500 accepted calls/key/month on Free; Pro placeholders 120/minute and 25,000/month. Response headers are authoritative for your key. This deployment may have generative tools disabled until the operator configures a provider. Grammar, citation and extractive summaries do not require one.","contact":{"name":"MetaPhrase operator","url":"https://metaphrase.msalman.com"}},"servers":[{"url":"https://metaphrase.msalman.com","description":"MetaPhrase origin; endpoint paths include /api/v1."}],"tags":[{"name":"paraphrase","description":"Rewrite text in one of seven modes while preserving its meaning."},{"name":"grammar","description":"Find language issues and return suggestions with corrected text, without an LLM."},{"name":"detect","description":"Estimate AI-like writing cues overall and for each sentence; results may be wrong."},{"name":"translate","description":"Translate text across 42 languages with source detection and RTL metadata."},{"name":"summarize","description":"Create paragraphs, bullets, or exact source key sentences."},{"name":"cite","description":"Generate a citation and BibTeX/RIS exports from source metadata, without an LLM."}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/paraphrase":{"post":{"operationId":"paraphrase","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/paraphrase\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/paraphrase\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.paraphrase({\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"text\\\":\\\"Good writing helps people understand an idea.\\\",\\\"mode\\\":\\\"standard\\\",\\\"synonym_strength\\\":50,\\\"action\\\":\\\"rewrite\\\",\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/paraphrase\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"text\":\"Good writing helps people understand an idea.\",\"mode\":\"standard\",\"synonym_strength\":50,\"action\":\"rewrite\",\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/paraphrase');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/paraphrase\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/paraphrase\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"text\": \"Good writing helps people understand an idea.\",\n  \"mode\": \"standard\",\n  \"synonym_strength\": 50,\n  \"action\": \"rewrite\",\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/paraphrase\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"text\":\"Good writing helps people understand an idea.\",\"mode\":\"standard\",\"synonym_strength\":50,\"action\":\"rewrite\",\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/paraphrase'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Rewrite text in one of seven modes while preserving its meaning.","description":"Rewrite text in one of seven modes while preserving its meaning.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/paraphrase.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["paraphrase"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/paraphraseRequest"},"example":{"text":"Good writing helps people understand an idea.","mode":"standard","synonym_strength":50,"action":"rewrite","stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/paraphraseResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000001","tool":"paraphrase","result":{"text":"Clear writing makes ideas easier to understand.","mode":"standard","synonym_strength":50,"changes":[{"text":"Clear writing makes ideas easier to understand.","changed":true}]},"usage":{"input_tokens":60,"output_tokens":20,"total_tokens":80,"estimated_cost_usd":0.000016,"usage_estimated":false,"cached":false,"provider":"primary","model":"gpt-6-luna"},"input_words":7,"output_words":7}},"text/event-stream":{"schema":{"type":"string"},"example":"event: meta\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000001\",\"tool\":\"paraphrase\"}\n\nevent: delta\ndata: {\"text_delta\":\"\"}\n\nevent: done\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000001\",\"tool\":\"paraphrase\",\"result\":{\"text\":\"Clear writing makes ideas easier to understand.\",\"mode\":\"standard\",\"synonym_strength\":50,\"changes\":[{\"text\":\"Clear writing makes ideas easier to understand.\",\"changed\":true}]},\"usage\":{\"input_tokens\":60,\"output_tokens\":20,\"total_tokens\":80,\"estimated_cost_usd\":0.000016,\"usage_estimated\":false,\"cached\":false,\"provider\":\"primary\",\"model\":\"gpt-6-luna\"},\"input_words\":7,\"output_words\":7}\n\n"}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.\n\nbudget_exceeded: The writing service has reached its configured spending limit. Fix: The operator must review usage and adjust the configured budget before more paid requests can run.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}},"budget_exceeded":{"value":{"error":{"code":"budget_exceeded","message":"The writing service has reached its configured spending limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#budget_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"502":{"description":"upstream_error: The writing provider returned an invalid response. Fix: Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.\n\noutput_truncated: The response reached its output limit before finishing. Fix: Use a shorter input or ask the operator to adjust the tool's output cap and chunk size.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_error":{"value":{"error":{"code":"upstream_error","message":"The writing provider returned an invalid response.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_error"}}},"output_truncated":{"value":{"error":{"code":"output_truncated","message":"The response reached its output limit before finishing.","docs_url":"https://metaphrase.msalman.com/docs/errors#output_truncated"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.\n\nprovider_not_configured: The writing provider is not configured yet. Fix: The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container.\n\nupstream_unavailable: The writing provider is temporarily unavailable. Fix: Retry with backoff. The operator can inspect provider availability without logging submitted text.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}},"provider_not_configured":{"value":{"error":{"code":"provider_not_configured","message":"The writing provider is not configured yet.","docs_url":"https://metaphrase.msalman.com/docs/errors#provider_not_configured"}}},"upstream_unavailable":{"value":{"error":{"code":"upstream_unavailable","message":"The writing provider is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_unavailable"}}}}}}},"504":{"description":"upstream_timeout: The writing provider took too long to respond. Fix: Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_timeout":{"value":{"error":{"code":"upstream_timeout","message":"The writing provider took too long to respond.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_timeout"}}}}}}}}}},"/api/v1/grammar":{"post":{"operationId":"grammar","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/grammar\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/grammar\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.grammar({\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"text\\\":\\\"The best ideas deserves to be shared.\\\",\\\"language\\\":\\\"en-US\\\",\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/grammar\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"text\":\"The best ideas deserves to be shared.\",\"language\":\"en-US\",\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/grammar');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/grammar\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/grammar\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"text\": \"The best ideas deserves to be shared.\",\n  \"language\": \"en-US\",\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/grammar\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"text\":\"The best ideas deserves to be shared.\",\"language\":\"en-US\",\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/grammar'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Find language issues and return suggestions with corrected text, without an LLM.","description":"Find language issues and return suggestions with corrected text, without an LLM.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/grammar.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["grammar"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/grammarRequest"},"example":{"text":"The best ideas deserves to be shared.","language":"en-US","stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/grammarResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000002","tool":"grammar","result":{"text":"The best ideas deserve to be shared.","original_text":"The best ideas deserves to be shared.","language":"en-US","matches":[{"id":"0-15","offset":15,"length":8,"message":"The verb form ‘deserves’ does not seem to match the subject ‘ideas’.","short_message":"","category":"grammar","rule_id":"SUBJECT_VERB_AGREEMENT_PLURAL","replacements":["deserve","deserved","will deserve"],"original":"deserves"}],"corrections_count":1},"usage":{"input_tokens":0,"output_tokens":0,"total_tokens":0,"estimated_cost_usd":0,"usage_estimated":false,"cached":false,"provider":"self_hosted","model":"LanguageTool 6.8"},"input_words":7,"output_words":7}}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"502":{"description":"upstream_error: The writing provider returned an invalid response. Fix: Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_error":{"value":{"error":{"code":"upstream_error","message":"The writing provider returned an invalid response.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_error"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}}}}}},"504":{"description":"upstream_timeout: The writing provider took too long to respond. Fix: Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_timeout":{"value":{"error":{"code":"upstream_timeout","message":"The writing provider took too long to respond.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_timeout"}}}}}}}}}},"/api/v1/detect":{"post":{"operationId":"detect","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/detect\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/detect\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.detect({\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"text\\\":\\\"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\\\",\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/detect\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"text\":\"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/detect');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/detect\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/detect\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"text\": \"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/detect\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"text\":\"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.\",\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/detect'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Estimate AI-like writing cues overall and for each sentence; results may be wrong.","description":"Estimate AI-like writing cues overall and for each sentence; results may be wrong.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/detect.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["detect"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/detectRequest"},"example":{"text":"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines. They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.","stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/detectResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000003","tool":"detect","result":{"text":"AI-like writing estimate: 50%\n\nAI detection is an uncalibrated estimate and may be wrong. Human writing can be flagged as AI, and AI writing can be missed. Never use this result alone to make decisions about a person.\n\n[50%] The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines.\n\n[50%] They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.","ai_estimate":50,"method":"llm_heuristic","disclaimer":"AI detection is an uncalibrated estimate and may be wrong. Human writing can be flagged as AI, and AI writing can be missed. Never use this result alone to make decisions about a person.","sentences":[{"text":"The research team spent several long months carefully studying how local people use public spaces in their neighborhood and listening to residents describe their daily routines.","offset":0,"length":177,"ai_estimate":50},{"text":"They found that shade, comfortable seating, and safe crossings mattered more to participants than expensive decorative features, so the final proposal focused on those practical needs.","offset":178,"length":184,"ai_estimate":50}]},"usage":{"input_tokens":140,"output_tokens":80,"total_tokens":220,"estimated_cost_usd":0.000054,"usage_estimated":false,"cached":false,"provider":"primary","model":"gpt-6-luna"},"input_words":52,"output_words":93}}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"422":{"description":"text_too_short: More text is needed for a meaningful estimate. Fix: Submit at least the documented minimum word count. Very short texts cannot be assessed meaningfully.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"text_too_short":{"value":{"error":{"code":"text_too_short","message":"More text is needed for a meaningful estimate.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_short"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.\n\nbudget_exceeded: The writing service has reached its configured spending limit. Fix: The operator must review usage and adjust the configured budget before more paid requests can run.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}},"budget_exceeded":{"value":{"error":{"code":"budget_exceeded","message":"The writing service has reached its configured spending limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#budget_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"502":{"description":"upstream_error: The writing provider returned an invalid response. Fix: Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.\n\noutput_truncated: The response reached its output limit before finishing. Fix: Use a shorter input or ask the operator to adjust the tool's output cap and chunk size.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_error":{"value":{"error":{"code":"upstream_error","message":"The writing provider returned an invalid response.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_error"}}},"output_truncated":{"value":{"error":{"code":"output_truncated","message":"The response reached its output limit before finishing.","docs_url":"https://metaphrase.msalman.com/docs/errors#output_truncated"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.\n\nprovider_not_configured: The writing provider is not configured yet. Fix: The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container.\n\nupstream_unavailable: The writing provider is temporarily unavailable. Fix: Retry with backoff. The operator can inspect provider availability without logging submitted text.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}},"provider_not_configured":{"value":{"error":{"code":"provider_not_configured","message":"The writing provider is not configured yet.","docs_url":"https://metaphrase.msalman.com/docs/errors#provider_not_configured"}}},"upstream_unavailable":{"value":{"error":{"code":"upstream_unavailable","message":"The writing provider is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_unavailable"}}}}}}},"504":{"description":"upstream_timeout: The writing provider took too long to respond. Fix: Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_timeout":{"value":{"error":{"code":"upstream_timeout","message":"The writing provider took too long to respond.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_timeout"}}}}}}}}}},"/api/v1/translate":{"post":{"operationId":"translate","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/translate\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/translate\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.translate({\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"text\\\":\\\"A good idea can come from anywhere.\\\",\\\"source_language\\\":\\\"auto\\\",\\\"target_language\\\":\\\"ur\\\",\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/translate\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"text\":\"A good idea can come from anywhere.\",\"source_language\":\"auto\",\"target_language\":\"ur\",\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/translate');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/translate\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/translate\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"text\": \"A good idea can come from anywhere.\",\n  \"source_language\": \"auto\",\n  \"target_language\": \"ur\",\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/translate\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"text\":\"A good idea can come from anywhere.\",\"source_language\":\"auto\",\"target_language\":\"ur\",\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/translate'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Translate text across 42 languages with source detection and RTL metadata.","description":"Translate text across 42 languages with source detection and RTL metadata.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/translate.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["translate"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/translateRequest"},"example":{"text":"A good idea can come from anywhere.","source_language":"auto","target_language":"ur","stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/translateResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000004","tool":"translate","result":{"text":"ایک اچھا خیال کہیں سے بھی آ سکتا ہے۔","source_language":"en","target_language":"ur","source_language_detected":true,"direction":"rtl"},"usage":{"input_tokens":60,"output_tokens":20,"total_tokens":80,"estimated_cost_usd":0.000016,"usage_estimated":false,"cached":false,"provider":"primary","model":"gpt-6-luna"},"input_words":7,"output_words":9}},"text/event-stream":{"schema":{"type":"string"},"example":"event: meta\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000004\",\"tool\":\"translate\"}\n\nevent: delta\ndata: {\"text_delta\":\"\"}\n\nevent: done\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000004\",\"tool\":\"translate\",\"result\":{\"text\":\"ایک اچھا خیال کہیں سے بھی آ سکتا ہے۔\",\"source_language\":\"en\",\"target_language\":\"ur\",\"source_language_detected\":true,\"direction\":\"rtl\"},\"usage\":{\"input_tokens\":60,\"output_tokens\":20,\"total_tokens\":80,\"estimated_cost_usd\":0.000016,\"usage_estimated\":false,\"cached\":false,\"provider\":\"primary\",\"model\":\"gpt-6-luna\"},\"input_words\":7,\"output_words\":9}\n\n"}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.\n\nbudget_exceeded: The writing service has reached its configured spending limit. Fix: The operator must review usage and adjust the configured budget before more paid requests can run.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}},"budget_exceeded":{"value":{"error":{"code":"budget_exceeded","message":"The writing service has reached its configured spending limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#budget_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"502":{"description":"upstream_error: The writing provider returned an invalid response. Fix: Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.\n\noutput_truncated: The response reached its output limit before finishing. Fix: Use a shorter input or ask the operator to adjust the tool's output cap and chunk size.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_error":{"value":{"error":{"code":"upstream_error","message":"The writing provider returned an invalid response.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_error"}}},"output_truncated":{"value":{"error":{"code":"output_truncated","message":"The response reached its output limit before finishing.","docs_url":"https://metaphrase.msalman.com/docs/errors#output_truncated"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.\n\nprovider_not_configured: The writing provider is not configured yet. Fix: The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container.\n\nupstream_unavailable: The writing provider is temporarily unavailable. Fix: Retry with backoff. The operator can inspect provider availability without logging submitted text.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}},"provider_not_configured":{"value":{"error":{"code":"provider_not_configured","message":"The writing provider is not configured yet.","docs_url":"https://metaphrase.msalman.com/docs/errors#provider_not_configured"}}},"upstream_unavailable":{"value":{"error":{"code":"upstream_unavailable","message":"The writing provider is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_unavailable"}}}}}}},"504":{"description":"upstream_timeout: The writing provider took too long to respond. Fix: Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_timeout":{"value":{"error":{"code":"upstream_timeout","message":"The writing provider took too long to respond.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_timeout"}}}}}}}}}},"/api/v1/summarize":{"post":{"operationId":"summarize","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/summarize\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/summarize\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.summarize({\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"text\\\":\\\"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\\\",\\\"format\\\":\\\"key_sentences\\\",\\\"length\\\":30,\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/summarize\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"text\":\"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\"format\":\"key_sentences\",\"length\":30,\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/summarize');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/summarize\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/summarize\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"text\": \"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\n  \"format\": \"key_sentences\",\n  \"length\": 30,\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/summarize\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"text\":\"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.\",\"format\":\"key_sentences\",\"length\":30,\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/summarize'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Create paragraphs, bullets, or exact source key sentences.","description":"Create paragraphs, bullets, or exact source key sentences.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/summarize.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["summarize"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/summarizeRequest"},"example":{"text":"Solar panels turn sunlight into electricity. Batteries store the energy for use at night. Regular maintenance keeps the system working efficiently.","format":"key_sentences","length":30,"stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/summarizeResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000005","tool":"summarize","result":{"text":"Solar panels turn sunlight into electricity.","format":"key_sentences","length":30,"sentences":[{"text":"Solar panels turn sunlight into electricity. ","offset":0,"length":45}]},"usage":{"input_tokens":0,"output_tokens":0,"total_tokens":0,"estimated_cost_usd":0,"usage_estimated":false,"cached":false,"provider":"self_hosted","model":"extractive_tfidf_v1"},"input_words":21,"output_words":6}},"text/event-stream":{"schema":{"type":"string"},"example":"event: meta\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000005\",\"tool\":\"summarize\"}\n\nevent: delta\ndata: {\"text_delta\":\"\"}\n\nevent: done\ndata: {\"request_id\":\"019b8df0-1234-4000-8000-000000000005\",\"tool\":\"summarize\",\"result\":{\"text\":\"Solar panels turn sunlight into electricity.\",\"format\":\"key_sentences\",\"length\":30,\"sentences\":[{\"text\":\"Solar panels turn sunlight into electricity. \",\"offset\":0,\"length\":45}]},\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"total_tokens\":0,\"estimated_cost_usd\":0,\"usage_estimated\":false,\"cached\":false,\"provider\":\"self_hosted\",\"model\":\"extractive_tfidf_v1\"},\"input_words\":21,\"output_words\":6}\n\n"}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.\n\nbudget_exceeded: The writing service has reached its configured spending limit. Fix: The operator must review usage and adjust the configured budget before more paid requests can run.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}},"budget_exceeded":{"value":{"error":{"code":"budget_exceeded","message":"The writing service has reached its configured spending limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#budget_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"502":{"description":"upstream_error: The writing provider returned an invalid response. Fix: Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility.\n\noutput_truncated: The response reached its output limit before finishing. Fix: Use a shorter input or ask the operator to adjust the tool's output cap and chunk size.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_error":{"value":{"error":{"code":"upstream_error","message":"The writing provider returned an invalid response.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_error"}}},"output_truncated":{"value":{"error":{"code":"output_truncated","message":"The response reached its output limit before finishing.","docs_url":"https://metaphrase.msalman.com/docs/errors#output_truncated"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.\n\nprovider_not_configured: The writing provider is not configured yet. Fix: The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container.\n\nupstream_unavailable: The writing provider is temporarily unavailable. Fix: Retry with backoff. The operator can inspect provider availability without logging submitted text.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}},"provider_not_configured":{"value":{"error":{"code":"provider_not_configured","message":"The writing provider is not configured yet.","docs_url":"https://metaphrase.msalman.com/docs/errors#provider_not_configured"}}},"upstream_unavailable":{"value":{"error":{"code":"upstream_unavailable","message":"The writing provider is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_unavailable"}}}}}}},"504":{"description":"upstream_timeout: The writing provider took too long to respond. Fix: Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"upstream_timeout":{"value":{"error":{"code":"upstream_timeout","message":"The writing provider took too long to respond.","docs_url":"https://metaphrase.msalman.com/docs/errors#upstream_timeout"}}}}}}}}}},"/api/v1/cite":{"post":{"operationId":"cite","x-codeSamples":[{"lang":"bash","label":"cURL","source":"#!/usr/bin/env bash\nset -euo pipefail\n: \"${METAPHRASE_API_KEY:?Set METAPHRASE_API_KEY in your backend environment}\"\nBASE_URL=\"${METAPHRASE_BASE_URL:-https://metaphrase.msalman.com}\"\ncurl --fail-with-body --silent --show-error \\\n  --request POST \"${BASE_URL%/}/api/v1/cite\" \\\n  --header \"Authorization: Bearer $METAPHRASE_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @- <<'JSON'\n{\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n}\nJSON\n"},{"lang":"javascript","label":"JavaScript (fetch)","source":"const key = process.env.METAPHRASE_API_KEY;\nif (!key) throw new Error(\"Set METAPHRASE_API_KEY on your backend\");\nconst base = (process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\").replace(/\\/$/, \"\");\nconst payload = {\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n};\nconst response = await fetch(base + \"/api/v1/cite\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer \" + key, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify(payload),\n  signal: AbortSignal.timeout(250000),\n});\nconst result = await response.json();\nif (!response.ok) {\n  console.error(response.status, result.error.code, result.error.message, result.error.docs_url);\n  process.exitCode = 1;\n} else {\n  console.log(JSON.stringify(result, null, 2));\n}\n"},{"lang":"javascript","label":"Node.js","source":"import { MetaPhrase, MetaPhraseError } from \"@metaphrase/sdk\";\nconst client = new MetaPhrase({\n  api_key: process.env.METAPHRASE_API_KEY,\n  base_url: process.env.METAPHRASE_BASE_URL ?? \"https://metaphrase.msalman.com\",\n});\ntry {\n  const result = await client.cite({\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n});\n  console.log(JSON.stringify(result, null, 2));\n} catch (error) {\n  if (error instanceof MetaPhraseError) console.error(error.status, error.code, error.message, error.docs_url);\n  else console.error(error);\n  process.exitCode = 1;\n}\n"},{"lang":"python","label":"Python","source":"import json\nimport os\nimport sys\nfrom urllib.request import Request, urlopen\nfrom urllib.error import HTTPError\n\nkey = os.environ[\"METAPHRASE_API_KEY\"]\nbase = os.environ.get(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").rstrip(\"/\")\npayload = json.loads(\"{\\\"source_type\\\":\\\"manual\\\",\\\"style\\\":\\\"apa\\\",\\\"fields\\\":{\\\"type\\\":\\\"book\\\",\\\"title\\\":\\\"A clear idea\\\",\\\"authors\\\":[{\\\"given\\\":\\\"Ada\\\",\\\"family\\\":\\\"Lovelace\\\"}],\\\"year\\\":2024,\\\"publisher\\\":\\\"Example Press\\\"},\\\"stream\\\":false}\")\nrequest = Request(\n    base + \"/api/v1/cite\",\n    data=json.dumps(payload, ensure_ascii=False).encode(\"utf-8\"),\n    headers={\"Authorization\": \"Bearer \" + key, \"Content-Type\": \"application/json\"},\n    method=\"POST\",\n)\ntry:\n    with urlopen(request, timeout=250) as response:\n        print(json.dumps(json.load(response), ensure_ascii=False, indent=2))\nexcept HTTPError as error:\n    print(error.code, error.read().decode(\"utf-8\"), file=sys.stderr)\n    sys.exit(1)\n"},{"lang":"php","label":"PHP","source":"<?php\ndeclare(strict_types=1);\n$key = getenv('METAPHRASE_API_KEY');\nif (!$key) { throw new RuntimeException('Set METAPHRASE_API_KEY on your backend'); }\n$base = rtrim(getenv('METAPHRASE_BASE_URL') ?: 'https://metaphrase.msalman.com', '/');\n$payload = json_decode('{\"source_type\":\"manual\",\"style\":\"apa\",\"fields\":{\"type\":\"book\",\"title\":\"A clear idea\",\"authors\":[{\"given\":\"Ada\",\"family\":\"Lovelace\"}],\"year\":2024,\"publisher\":\"Example Press\"},\"stream\":false}', true, 512, JSON_THROW_ON_ERROR);\n$curl = curl_init($base . '/api/v1/cite');\ncurl_setopt_array($curl, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_TIMEOUT => 250,\n    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],\n    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),\n]);\n$body = curl_exec($curl);\nif ($body === false) { throw new RuntimeException(curl_error($curl)); }\n$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);\ncurl_close($curl);\n$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);\necho json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;\nif ($status >= 400) { exit(1); }\n"},{"lang":"java","label":"Java","source":"import java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.time.Duration;\n\npublic class MetaPhraseExample {\n  public static void main(String[] args) throws Exception {\n    String key = System.getenv(\"METAPHRASE_API_KEY\");\n    if (key == null || key.isBlank()) throw new IllegalStateException(\"Set METAPHRASE_API_KEY\");\n    String base = System.getenv().getOrDefault(\"METAPHRASE_BASE_URL\", \"https://metaphrase.msalman.com\").replaceAll(\"/+$\", \"\");\n    String payload = \"\"\"\n{\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n}\n\"\"\";\n    HttpRequest request = HttpRequest.newBuilder(URI.create(base + \"/api/v1/cite\"))\n        .timeout(Duration.ofSeconds(250))\n        .header(\"Authorization\", \"Bearer \" + key)\n        .header(\"Content-Type\", \"application/json\")\n        .POST(HttpRequest.BodyPublishers.ofString(payload))\n        .build();\n    HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());\n    System.out.println(response.body());\n    if (response.statusCode() >= 400) throw new java.io.IOException(\"HTTP \" + response.statusCode() + \": \" + response.body());\n  }\n}\n"},{"lang":"csharp","label":"C#","source":"using System.Net.Http.Headers;\nusing System.Text;\n\nstring key = Environment.GetEnvironmentVariable(\"METAPHRASE_API_KEY\")\n    ?? throw new InvalidOperationException(\"Set METAPHRASE_API_KEY\");\nstring baseUrl = (Environment.GetEnvironmentVariable(\"METAPHRASE_BASE_URL\") ?? \"https://metaphrase.msalman.com\").TrimEnd('/');\nstring payload = \"\"\"\n{\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n}\n\"\"\";\nusing var client = new HttpClient { Timeout = TimeSpan.FromSeconds(250) };\nclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\nusing var content = new StringContent(payload, Encoding.UTF8, \"application/json\");\nusing var response = await client.PostAsync(baseUrl + \"/api/v1/cite\", content);\nstring result = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(result);\nif (!response.IsSuccessStatusCode) throw new HttpRequestException($\"HTTP {(int)response.StatusCode}: {result}\");\n"},{"lang":"go","label":"Go","source":"package main\n\nimport (\n  \"bytes\"\n  \"fmt\"\n  \"io\"\n  \"net/http\"\n  \"os\"\n  \"strings\"\n  \"time\"\n)\n\nfunc main() {\n  key := os.Getenv(\"METAPHRASE_API_KEY\")\n  if key == \"\" { panic(\"Set METAPHRASE_API_KEY\") }\n  base := os.Getenv(\"METAPHRASE_BASE_URL\")\n  if base == \"\" { base = \"https://metaphrase.msalman.com\" }\n  payload := []byte(`{\n  \"source_type\": \"manual\",\n  \"style\": \"apa\",\n  \"fields\": {\n    \"type\": \"book\",\n    \"title\": \"A clear idea\",\n    \"authors\": [\n      {\n        \"given\": \"Ada\",\n        \"family\": \"Lovelace\"\n      }\n    ],\n    \"year\": 2024,\n    \"publisher\": \"Example Press\"\n  },\n  \"stream\": false\n}`)\n  request, err := http.NewRequest(http.MethodPost, strings.TrimRight(base, \"/\") + \"/api/v1/cite\", bytes.NewReader(payload))\n  if err != nil { panic(err) }\n  request.Header.Set(\"Authorization\", \"Bearer \" + key)\n  request.Header.Set(\"Content-Type\", \"application/json\")\n  client := &http.Client{Timeout: 250 * time.Second}\n  response, err := client.Do(request)\n  if err != nil { panic(err) }\n  defer response.Body.Close()\n  body, err := io.ReadAll(response.Body)\n  if err != nil { panic(err) }\n  fmt.Println(string(body))\n  if response.StatusCode >= 400 { os.Exit(1) }\n}\n"},{"lang":"dart","label":"Flutter / Dart","source":"import 'dart:convert';\nimport 'dart:io';\n\nFuture<void> main() async {\n  final key = Platform.environment['METAPHRASE_API_KEY'];\n  if (key == null || key.isEmpty) throw StateError('Set METAPHRASE_API_KEY on your backend');\n  final base = (Platform.environment['METAPHRASE_BASE_URL'] ?? 'https://metaphrase.msalman.com').replaceFirst(RegExp(r'/+$'), '');\n  final payload = jsonDecode(r'''{\"source_type\":\"manual\",\"style\":\"apa\",\"fields\":{\"type\":\"book\",\"title\":\"A clear idea\",\"authors\":[{\"given\":\"Ada\",\"family\":\"Lovelace\"}],\"year\":2024,\"publisher\":\"Example Press\"},\"stream\":false}''');\n  final client = HttpClient()..connectionTimeout = const Duration(seconds: 30);\n  try {\n    final request = await client.postUrl(Uri.parse('$base/api/v1/cite'));\n    request.headers.set(HttpHeaders.authorizationHeader, 'Bearer $key');\n    request.headers.contentType = ContentType.json;\n    request.write(jsonEncode(payload));\n    final response = await request.close().timeout(const Duration(seconds: 250));\n    final body = await utf8.decoder.bind(response).join();\n    stdout.writeln(body);\n    if (response.statusCode >= 400) exitCode = 1;\n  } finally {\n    client.close(force: true);\n  }\n}\n"}],"summary":"Generate a citation and BibTeX/RIS exports from source metadata, without an LLM.","description":"Generate a citation and BibTeX/RIS exports from source metadata, without an LLM.\n\nFull reference, complete runnable samples and fixes: https://metaphrase.msalman.com/docs/cite.md\n\nAuthentication: Authorization: Bearer <key>. Keep keys in backend environment variables. Accepted calls consume per-key monthly quota, including cache hits and upstream errors. Streaming errors after headers are sent use an SSE error event with the same JSON error body. See https://metaphrase.msalman.com/docs/streaming.md.","tags":["cite"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/citeRequest"},"example":{"source_type":"manual","style":"apa","fields":{"type":"book","title":"A clear idea","authors":[{"given":"Ada","family":"Lovelace"}],"year":2024,"publisher":"Example Press"},"stream":false}}}},"responses":{"200":{"description":"Successful result. Examples are illustrative; writing and retrieved metadata can vary.","headers":{"X-Request-Id":{"description":"Server-generated UUID; use it for support and logging.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Remaining":{"description":"Remaining accepted calls in the key's current 60-second window.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Remaining accepted calls in the key's UTC calendar month.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/citeResponse"},"example":{"request_id":"019b8df0-1234-4000-8000-000000000006","tool":"cite","result":{"text":"Lovelace, A. (2024). A clear idea. Example Press.","style":"apa","style_name":"APA 7","source_type":"manual","metadata":{"type":"book","title":"A clear idea","authors":[{"given":"Ada","family":"Lovelace"}],"year":2024,"publisher":"Example Press"},"bibtex":"@book{mpfda3a81f9b10,\n  author = {Lovelace, Ada},\n  title = {A clear idea},\n  year = {2024},\n  publisher = {Example Press}\n}\n","ris":"TY  - BOOK\nAU  - Lovelace, Ada\nTI  - A clear idea\nPY  - 2024\nPB  - Example Press\nER  -\n","warnings":[]},"usage":{"input_tokens":0,"output_tokens":0,"total_tokens":0,"estimated_cost_usd":0,"usage_estimated":false,"cached":false,"provider":"self_hosted","model":"citation.js_0.9.0"},"input_words":3,"output_words":8}}}},"400":{"description":"invalid_request: Check the request fields and their allowed values. Fix: Send the documented JSON fields with the correct types. Unknown fields are rejected.\n\ninvalid_json: The request body is not valid JSON. Fix: Serialize the request with JSON.stringify or your language's JSON encoder.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"Check the request fields and their allowed values.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_request"}}},"invalid_json":{"value":{"error":{"code":"invalid_json","message":"The request body is not valid JSON.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_json"}}}}}}},"401":{"description":"unauthorized: A valid API key is required. Fix: Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required.","docs_url":"https://metaphrase.msalman.com/docs/errors#unauthorized"}}}}}}},"403":{"description":"forbidden: This action is not available to this account. Fix: Check account status and the key's access permissions.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"forbidden":{"value":{"error":{"code":"forbidden","message":"This action is not available to this account.","docs_url":"https://metaphrase.msalman.com/docs/errors#forbidden"}}}}}}},"404":{"description":"not_found: This resource does not exist. Fix: Check the API version, endpoint name, and resource identifier.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"This resource does not exist.","docs_url":"https://metaphrase.msalman.com/docs/errors#not_found"}}}}}}},"405":{"description":"method_not_allowed: This HTTP method is not supported. Fix: Use POST for processing endpoints and the method documented for dashboard routes.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"method_not_allowed":{"value":{"error":{"code":"method_not_allowed","message":"This HTTP method is not supported.","docs_url":"https://metaphrase.msalman.com/docs/errors#method_not_allowed"}}}}}}},"413":{"description":"body_too_large: The request body exceeds the allowed size. Fix: Reduce the payload and split long documents at sentence boundaries.\n\ntext_too_long: The text exceeds the configured character limit. Fix: Use the max_input_chars value in the API specification and split longer documents.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"body_too_large":{"value":{"error":{"code":"body_too_large","message":"The request body exceeds the allowed size.","docs_url":"https://metaphrase.msalman.com/docs/errors#body_too_large"}}},"text_too_long":{"value":{"error":{"code":"text_too_long","message":"The text exceeds the configured character limit.","docs_url":"https://metaphrase.msalman.com/docs/errors#text_too_long"}}}}}}},"415":{"description":"unsupported_media_type: Send application/json content. Fix: Set Content-Type: application/json. File uploads use their separate documented route.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"unsupported_media_type":{"value":{"error":{"code":"unsupported_media_type","message":"Send application/json content.","docs_url":"https://metaphrase.msalman.com/docs/errors#unsupported_media_type"}}}}}}},"422":{"description":"invalid_source: The source could not be used. Fix: Check the DOI, ISBN, or public HTTP URL, or use manual citation fields.\n\nsource_unavailable: Source metadata could not be retrieved. Fix: Try a DOI or ISBN, or enter the source details manually.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_source":{"value":{"error":{"code":"invalid_source","message":"The source could not be used.","docs_url":"https://metaphrase.msalman.com/docs/errors#invalid_source"}}},"source_unavailable":{"value":{"error":{"code":"source_unavailable","message":"Source metadata could not be retrieved.","docs_url":"https://metaphrase.msalman.com/docs/errors#source_unavailable"}}}}}}},"429":{"description":"rate_limited: Too many requests. Please wait and try again. Fix: Wait for Retry-After seconds and use exponential backoff with jitter.\n\nquota_exceeded: The monthly usage quota has been reached. Fix: Wait for the next UTC calendar month or ask an administrator to change the plan.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Please wait and try again.","docs_url":"https://metaphrase.msalman.com/docs/errors#rate_limited"}}},"quota_exceeded":{"value":{"error":{"code":"quota_exceeded","message":"The monthly usage quota has been reached.","docs_url":"https://metaphrase.msalman.com/docs/errors#quota_exceeded"}}}}}}},"500":{"description":"internal_error: The request could not be completed. Fix: Retry once. If it persists, provide the X-Request-Id header to the operator.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"The request could not be completed.","docs_url":"https://metaphrase.msalman.com/docs/errors#internal_error"}}}}}}},"503":{"description":"service_unavailable: A required service is temporarily unavailable. Fix: Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health.","headers":{},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"A required service is temporarily unavailable.","docs_url":"https://metaphrase.msalman.com/docs/errors#service_unavailable"}}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"mp_live_<43 URL-safe characters>","description":"Create a key at /dashboard and save it as METAPHRASE_API_KEY on your backend. Full keys are shown only once."}},"schemas":{"paraphraseRequest":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":20000,"pattern":"\\S","description":"Plain text. Limit counts Unicode code points."},"mode":{"default":"standard","type":"string","enum":["standard","fluent","formal","simple","creative","shorten","expand"],"description":"Rewrite style. All seven modes preserve source language, names, facts and meaning."},"synonym_strength":{"default":50,"type":"integer","minimum":0,"maximum":100,"description":"Vocabulary change strength, from 0 (minimal) to 100 (strong)."},"action":{"default":"rewrite","type":"string","enum":["rewrite","alternatives"],"description":"rewrite returns rewritten text; alternatives returns context-appropriate alternatives for target_word."},"target_word":{"type":"string","maxLength":80,"description":"Required for action=alternatives. Must appear in text; returns up to eight alternatives, at most 80 characters each."},"stream":{"default":false,"type":"boolean","description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"required":["text"],"additionalProperties":false,"allOf":[{"if":{"properties":{"action":{"const":"alternatives"}},"required":["action"]},"then":{"required":["target_word"],"properties":{"target_word":{"minLength":1,"pattern":"\\\\S"}}}}]},"paraphraseResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"paraphrase"},"result":{"type":"object","properties":{"text":{"type":"string"},"mode":{"type":"string","enum":["standard","fluent","formal","simple","creative","shorten","expand"]},"synonym_strength":{"type":"integer","minimum":0,"maximum":100},"changes":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"changed":{"type":"boolean"}},"required":["text","changed"],"additionalProperties":false}},"alternatives":{"maxItems":8,"type":"array","items":{"type":"string"}},"target_word":{"type":"string"}},"required":["text","mode","synonym_strength","changes"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"grammarRequest":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":20000,"pattern":"\\S","description":"Plain text. Limit counts Unicode code points."},"language":{"default":"en-US","type":"string","enum":["auto","ar","ast-ES","be-BY","br-FR","ca-ES","ca-ES-valencia","ca-ES-balear","da-DK","de","de-DE","de-AT","de-CH","de-DE-x-simple-language","el-GR","en","en-US","en-GB","en-AU","en-CA","en-NZ","en-ZA","eo","es","es-AR","fa","fr","fr-CA","fr-CH","fr-BE","ga-IE","gl-ES","it","ja-JP","km-KH","nl","nl-BE","pl-PL","pt","pt-PT","pt-BR","pt-AO","pt-MZ","ro-RO","ru-RU","sk-SK","sl-SI","sv","ta-IN","tl-PH","uk-UA","zh-CN","crh-UA","nl-NL","de-DE-x-simple-language-DE","es-ES","it-IT","fa-IR","sv-SE","de-LU","fr-FR"],"description":"A LanguageTool language code, or auto. LanguageTool supports only the listed codes; Urdu/Hindi are translation targets, not grammar languages."},"stream":{"default":false,"type":"boolean","const":false,"description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"required":["text"],"additionalProperties":false},"grammarResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"grammar"},"result":{"type":"object","properties":{"text":{"type":"string"},"original_text":{"type":"string"},"language":{"type":"string"},"matches":{"maxItems":1500,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"offset":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"UTF-16 code-unit offset into original_text, matching JavaScript string indices."},"length":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Length in UTF-16 code units."},"message":{"type":"string"},"short_message":{"type":"string"},"category":{"type":"string","enum":["grammar","spelling","punctuation","style"]},"rule_id":{"type":"string"},"replacements":{"maxItems":5,"type":"array","items":{"type":"string"}},"original":{"type":"string"}},"required":["id","offset","length","message","short_message","category","rule_id","replacements","original"],"additionalProperties":false}},"corrections_count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["text","original_text","language","matches","corrections_count"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"detectRequest":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":20000,"pattern":"\\S","description":"Plain text. Limit counts Unicode code points. At least 50 words are required. Scores are uncalibrated estimates, not authorship evidence.","x-min-words":50},"stream":{"default":false,"type":"boolean","const":false,"description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"required":["text"],"additionalProperties":false},"detectResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"detect"},"result":{"type":"object","properties":{"text":{"type":"string"},"ai_estimate":{"type":"integer","minimum":0,"maximum":100},"method":{"type":"string","const":"llm_heuristic"},"disclaimer":{"type":"string"},"sentences":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"offset":{"type":"integer","minimum":0,"maximum":9007199254740991},"length":{"type":"integer","minimum":0,"maximum":9007199254740991},"ai_estimate":{"type":"integer","minimum":0,"maximum":100}},"required":["text","offset","length","ai_estimate"],"additionalProperties":false}}},"required":["text","ai_estimate","method","disclaimer","sentences"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"translateRequest":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":20000,"pattern":"\\S","description":"Plain text. Limit counts Unicode code points."},"source_language":{"default":"auto","type":"string","enum":["auto","en","ur","hi","ar","es","fr","de","pt","it","nl","pl","uk","ru","tr","fa","he","bn","pa","ta","te","mr","gu","ne","si","zh","zh-TW","ja","ko","id","ms","vi","th","tl","sv","da","no","fi","el","cs","ro","hu","sw"],"description":"Source language code or auto. Detection is heuristic and may be uncertain."},"target_language":{"type":"string","enum":["en","ur","hi","ar","es","fr","de","pt","it","nl","pl","uk","ru","tr","fa","he","bn","pa","ta","te","mr","gu","ne","si","zh","zh-TW","ja","ko","id","ms","vi","th","tl","sv","da","no","fi","el","cs","ro","hu","sw"],"description":"Required translation target language code. ur/ar/fa/he return direction=rtl."},"stream":{"default":false,"type":"boolean","description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"required":["text","target_language"],"additionalProperties":false},"translateResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"translate"},"result":{"type":"object","properties":{"text":{"type":"string"},"source_language":{"type":"string","description":"Heuristically detected source code or und if unknown; explicit source is returned unchanged."},"target_language":{"type":"string","enum":["en","ur","hi","ar","es","fr","de","pt","it","nl","pl","uk","ru","tr","fa","he","bn","pa","ta","te","mr","gu","ne","si","zh","zh-TW","ja","ko","id","ms","vi","th","tl","sv","da","no","fi","el","cs","ro","hu","sw"]},"source_language_detected":{"type":"boolean"},"direction":{"type":"string","enum":["rtl","ltr"]}},"required":["text","source_language","target_language","source_language_detected","direction"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"summarizeRequest":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":20000,"pattern":"\\S","description":"Plain text. Limit counts Unicode code points."},"format":{"default":"paragraph","type":"string","enum":["paragraph","bullets","key_sentences"],"description":"paragraph or bullets use an LLM; key_sentences selects exact source sentences locally without an LLM."},"length":{"default":30,"type":"integer","minimum":10,"maximum":70,"description":"Approximate summary length as a percentage of source words. Whole sentences may exceed the target."},"stream":{"default":false,"type":"boolean","description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"required":["text"],"additionalProperties":false},"summarizeResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"summarize"},"result":{"type":"object","properties":{"text":{"type":"string"},"format":{"type":"string","enum":["paragraph","bullets","key_sentences"]},"length":{"type":"integer","minimum":10,"maximum":70},"sentences":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"offset":{"type":"integer","minimum":0,"maximum":9007199254740991},"length":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["text","offset","length"],"additionalProperties":false}}},"required":["text","format","length"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"citeRequest":{"type":"object","properties":{"source_type":{"default":"auto","type":"string","enum":["auto","url","doi","isbn","manual"],"description":"auto recognizes DOI, public HTTP(S) URL or ISBN; manual requires fields instead of source."},"source":{"type":"string","minLength":1,"maxLength":2048,"description":"A DOI (plain or doi.org URL), a checksum-valid ISBN-10/13, or a public HTTP(S) page URL. Private networks, credentials and nonstandard ports are rejected."},"style":{"default":"apa","type":"string","enum":["apa","mla","chicago","harvard","ieee"],"description":"apa=APA 7; mla=MLA 9; chicago=Chicago 18 author-date; harvard=Cite Them Right 12; ieee=IEEE."},"fields":{"type":"object","properties":{"type":{"default":"webpage","type":"string","enum":["webpage","book","article-journal"],"description":"Source kind used by the citation formatter."},"title":{"type":"string","minLength":1,"maxLength":500,"description":"Source title, preserved as metadata; verify against the original source."},"authors":{"default":[],"maxItems":50,"type":"array","items":{"type":"object","properties":{"given":{"type":"string","maxLength":120,"description":"Given names or initials."},"family":{"type":"string","maxLength":120,"description":"Family name. Keep compound surnames together."},"literal":{"type":"string","maxLength":250,"description":"Organization or literal author name; use instead of given/family."}},"additionalProperties":false,"anyOf":[{"required":["family"],"properties":{"family":{"minLength":1,"pattern":"\\S"}}},{"required":["literal"],"properties":{"literal":{"minLength":1,"pattern":"\\S"}}}]},"description":"Up to 50 authors. Each needs family or literal. Use given/family for people and literal for organizations."},"year":{"type":"integer","minimum":1,"maximum":9999,"description":"Publication year (1–9999)."},"month":{"type":"integer","minimum":1,"maximum":12,"description":"Publication month (1–12); requires year."},"day":{"type":"integer","minimum":1,"maximum":31,"description":"Valid calendar day; requires month and year."},"url":{"type":"string","maxLength":2048,"format":"uri","description":"HTTP(S) source URL; manual URLs are formatted, never fetched.","pattern":"^[Hh][Tt][Tt][Pp][Ss]?://"},"publisher":{"type":"string","maxLength":250,"description":"Publisher or website name."},"container_title":{"type":"string","maxLength":300,"description":"Journal or containing publication title."},"volume":{"type":"string","maxLength":40,"description":"Journal volume."},"issue":{"type":"string","maxLength":40,"description":"Journal issue."},"pages":{"type":"string","maxLength":80,"description":"Page range, for example 357-362."},"doi":{"type":"string","maxLength":255,"description":"Manual DOI metadata; not fetched in manual mode."},"isbn":{"type":"string","maxLength":25,"description":"Manual ISBN metadata; not fetched in manual mode."},"accessed_date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Date accessed, YYYY-MM-DD."}},"required":["title"],"additionalProperties":false,"description":"Manual source metadata. Required only for source_type=manual; title is required. Other missing metadata is reported in warnings.","allOf":[{"if":{"required":["month"]},"then":{"required":["year"]}},{"if":{"required":["day"]},"then":{"required":["year","month"]}}]},"stream":{"default":false,"type":"boolean","const":false,"description":"Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON."}},"additionalProperties":false,"allOf":[{"if":{"properties":{"source_type":{"const":"manual"}},"required":["source_type"]},"then":{"required":["fields"]},"else":{"required":["source"],"not":{"required":["fields"]}}}]},"citeResponse":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tool":{"type":"string","const":"cite"},"result":{"type":"object","properties":{"text":{"type":"string"},"style":{"type":"string","enum":["apa","mla","chicago","harvard","ieee"]},"style_name":{"type":"string"},"source_type":{"type":"string","enum":["url","doi","isbn","manual"]},"metadata":{"type":"object","properties":{"type":{"default":"webpage","type":"string","enum":["webpage","book","article-journal"]},"title":{"type":"string","minLength":1,"maxLength":500},"authors":{"default":[],"maxItems":50,"type":"array","items":{"type":"object","properties":{"given":{"type":"string","maxLength":120},"family":{"type":"string","maxLength":120},"literal":{"type":"string","maxLength":250}},"additionalProperties":false}},"year":{"type":"integer","minimum":1,"maximum":9999},"month":{"type":"integer","minimum":1,"maximum":12},"day":{"type":"integer","minimum":1,"maximum":31},"url":{"type":"string","maxLength":2048,"format":"uri"},"publisher":{"type":"string","maxLength":250},"container_title":{"type":"string","maxLength":300},"volume":{"type":"string","maxLength":40},"issue":{"type":"string","maxLength":40},"pages":{"type":"string","maxLength":80},"doi":{"type":"string","maxLength":255},"isbn":{"type":"string","maxLength":25},"accessed_date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"}},"required":["type","title","authors"],"additionalProperties":false},"bibtex":{"type":"string"},"ris":{"type":"string"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["text","style","style_name","source_type","metadata","bibtex","ris","warnings"],"additionalProperties":false},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":0,"maximum":9007199254740991},"estimated_cost_usd":{"type":"number","minimum":0},"usage_estimated":{"type":"boolean"},"cached":{"type":"boolean"},"provider":{"type":"string"},"model":{"type":"string"}},"required":["input_tokens","output_tokens","total_tokens","estimated_cost_usd","usage_estimated","cached","provider","model"],"additionalProperties":false},"input_words":{"type":"integer","minimum":0,"maximum":9007199254740991},"output_words":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["request_id","tool","result","usage","input_words","output_words"],"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_file","invalid_request","invalid_json","unsupported_media_type","body_too_large","text_too_long","unauthorized","forbidden","rate_limited","quota_exceeded","budget_exceeded","verification_required","provider_not_configured","upstream_unavailable","upstream_timeout","upstream_error","output_truncated","service_unavailable","invalid_source","source_unavailable","text_too_short","not_found","method_not_allowed","conflict","internal_error"]},"message":{"type":"string"},"docs_url":{"type":"string","format":"uri"}},"required":["code","message","docs_url"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}