{"openapi":"3.1.0","info":{"title":"CTAI API","version":"1.0.0","description":"Concordance-consistent linguistic analysis and AI translation of Arabic and Persian Bahá'í texts. The Jafar concordance engine indexes 105,000+ occurrences across 4,000+ roots from Shoghi Effendi's translations.","contact":{"name":"CTAI","url":"https://ctai.info"}},"servers":[{"url":"https://ctai.info/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/":{"get":{"summary":"OpenAPI specification","description":"Returns this OpenAPI 3.1 JSON spec. No authentication required.","security":[],"responses":{"200":{"description":"OpenAPI spec","content":{"application/json":{}}}}}},"/jafar":{"post":{"summary":"Jafar enrichment report","description":"Full linguistic enrichment for an Arabic or Persian passage. Tokenizes the source text, looks up every root in the Jafar concordance, and returns rendering spectrums, forms, and cross-references. By default, Haiku scores each root for relevance to the passage and prunes noise.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"Arabic or Persian source text"},"source_lang":{"type":"string","enum":["ar","fa"],"default":"ar"},"translation":{"type":"string","description":"Optional English translation for alignment"},"alignment":{"type":"array","description":"Optional pre-computed alignment pairs"},"filter":{"type":"boolean","default":true,"description":"Use AI relevance filtering to prune irrelevant roots (costs ~$0.001)"}}}}}},"responses":{"200":{"description":"Enrichment report","content":{"application/json":{"schema":{"type":"object","properties":{"source_text":{"type":"string"},"source_lang":{"type":"string"},"gloss":{"type":"string","description":"Word-by-word gloss of the source"},"enriched_terms":{"type":"array","items":{"$ref":"#/components/schemas/EnrichedTerm"}},"term_count":{"type":"integer"},"filtered":{"type":"boolean"},"filter_cost_usd":{"type":"number"}}}}}}}}},"/concordance":{"post":{"summary":"Quick phrase lookup","description":"Lighter than /jafar — returns matching roots and occurrences for an Arabic/Persian phrase without full enrichment or filtering.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phrase"],"properties":{"phrase":{"type":"string","description":"Arabic or Persian word/phrase to look up"},"source_lang":{"type":"string","enum":["ar","fa"],"default":"ar"}}}}}},"responses":{"200":{"description":"Concordance results"}}}},"/english/{word}":{"get":{"summary":"English rendering spectrum","description":"Given an English word, returns every Arabic/Persian root that Shoghi Effendi translated as that word. Each root includes its full rendering spectrum (all English words this root was translated as, with counts), Arabic forms seen, and example references. Use this to understand the semantic range of a translation choice.","parameters":[{"name":"word","in":"path","required":true,"schema":{"type":"string"},"description":"English word slug (e.g., \"glory\", \"sovereignty\", \"light\")"}],"responses":{"200":{"description":"Word analysis","content":{"application/json":{"schema":{"type":"object","properties":{"word":{"type":"string"},"slug":{"type":"string"},"total_occurrences":{"type":"integer"},"root_count":{"type":"integer"},"roots":{"type":"array","items":{"$ref":"#/components/schemas/EnglishWordRoot"}},"see_also":{"type":"array","items":{"type":"object","properties":{"word":{"type":"string"},"slug":{"type":"string"},"count":{"type":"integer"}}}}}}}}},"404":{"description":"No occurrences found"}}}},"/roots":{"get":{"summary":"Search/browse roots","description":"List or search Arabic/Persian roots in the Jafar concordance.","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by transliteration, meaning, or Arabic script"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Root list","content":{"application/json":{"schema":{"type":"object","properties":{"roots":{"type":"array","items":{"$ref":"#/components/schemas/Root"}},"count":{"type":"integer"},"offset":{"type":"integer"}}}}}}}}},"/roots/{slug}":{"get":{"summary":"Root detail with rendering spectrum","description":"Full detail for a single root: all English renderings with frequency counts, Arabic forms, and related roots.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Root slug (e.g., \"n-w-r\", \"z-h-r\")"}],"responses":{"200":{"description":"Root detail","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"root":{"type":"string"},"transliteration":{"type":"string"},"meaning":{"type":"string"},"is_name":{"type":"boolean"},"occurrence_count":{"type":"integer"},"rendering_count":{"type":"integer"},"rendering_spectrum":{"type":"array","items":{"$ref":"#/components/schemas/SpectrumEntry"}},"related_roots":{"type":"array","items":{"$ref":"#/components/schemas/Root"}}}}}}},"404":{"description":"Root not found"}}}},"/translate":{"post":{"summary":"Submit text for AI translation","description":"Translates Arabic or Persian text using the CTAI pipeline (concordance-informed, Shoghi Effendi-consistent terminology). Admin users are not billed. Non-admin users are charged via Stripe at 2x AI cost.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text","lang"],"properties":{"text":{"type":"string","description":"Arabic or Persian source text"},"lang":{"type":"string","enum":["ar","fa"]},"style":{"type":"string","default":"literary","description":"Translation style"},"return_url":{"type":"string","description":"Redirect URL after Stripe payment"},"cancel_url":{"type":"string","description":"Redirect URL on payment cancel"}}}}}},"responses":{"201":{"description":"Job created","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["processing","pending_payment"]},"poll_url":{"type":"string"}}}}}}}}},"/translate/estimate":{"post":{"summary":"Estimate translation cost","description":"Returns cost estimate for translating the given text without starting a job.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text","lang"],"properties":{"text":{"type":"string"},"lang":{"type":"string","enum":["ar","fa"]}}}}}},"responses":{"200":{"description":"Cost estimate"}}}},"/translate/{jobId}":{"get":{"summary":"Translation job status","description":"Poll for status of a submitted translation job. Returns the translated text when complete.","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status"},"404":{"description":"Job not found"}}}},"/keys":{"post":{"summary":"Create API key","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","default":"Default","maxLength":64}}}}}},"responses":{"201":{"description":"Key created (save the key — cannot be retrieved again)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}}}},"get":{"summary":"List API keys","responses":{"200":{"description":"All keys for this user","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}}}}},"/keys/{id}":{"delete":{"summary":"Revoke API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked"}}},"patch":{"summary":"Rename API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":64}}}}}},"responses":{"200":{"description":"Key renamed"}}}},"/keys/{id}/rotate":{"post":{"summary":"Rotate API key","description":"Revokes the existing key and creates a new one with the same name.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"New key created, old key revoked"}}}},"/billing/setup":{"post":{"summary":"Save payment method","description":"Creates a Stripe SetupIntent for saving a card. Use the returned client_secret with Stripe.js.","responses":{"200":{"description":"Setup intent details"}}}},"/billing/method":{"get":{"summary":"Check saved payment method","responses":{"200":{"description":"Payment method status"}}}},"/usage":{"get":{"summary":"Usage breakdown","parameters":[{"name":"key_id","in":"query","schema":{"type":"string"},"description":"Filter to a specific key"},{"name":"days","in":"query","schema":{"type":"integer","default":30,"maximum":365}}],"responses":{"200":{"description":"Usage by service and date"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key from POST /api/v1/keys. Format: Authorization: Bearer ctai_<key>"}},"schemas":{"Root":{"type":"object","properties":{"slug":{"type":"string","example":"n-w-r"},"root":{"type":"string","example":"ن-و-ر","description":"Arabic root letters"},"transliteration":{"type":"string","example":"n-w-r"},"meaning":{"type":"string","example":"light; illuminate"},"is_name":{"type":"boolean"},"occurrence_count":{"type":"integer"}}},"SpectrumEntry":{"type":"object","description":"One English rendering with its frequency in the corpus","properties":{"rendering":{"type":"string","example":"light"},"count":{"type":"integer","example":89},"pct":{"type":"integer","description":"Percentage of total occurrences for this root"},"forms":{"type":"array","items":{"type":"string"},"description":"Arabic forms that produced this rendering"}}},"EnrichedTerm":{"type":"object","description":"A term from the Jafar concordance enrichment pipeline","properties":{"term":{"type":"string"},"root":{"type":"string"},"transliteration":{"type":"string"},"literal":{"type":"string"},"se_rendering":{"type":"string","description":"Shoghi Effendi's rendering of this term"},"note":{"type":"string"},"occurrence_count":{"type":"integer"},"rendering_spectrum":{"type":"array","items":{"$ref":"#/components/schemas/SpectrumEntry"}},"is_deviation":{"type":"boolean"},"deviation_label":{"type":"string","nullable":true,"enum":["unique","distinctive",null]},"forms_in_passage":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string"},"translit":{"type":"string"},"se":{"type":"string"}}}},"cross_refs":{"type":"array","description":"Up to 8 example usages from other passages, diversified across works","items":{"type":"object","properties":{"work":{"type":"string"},"para":{"type":"integer"},"snippet":{"type":"string","description":"English rendering in context"}}}}}},"EnglishWordRoot":{"type":"object","description":"A root that produces a given English rendering","properties":{"root":{"type":"string"},"slug":{"type":"string"},"transliteration":{"type":"string"},"meaning":{"type":"string"},"occurrence_count":{"type":"integer","description":"How many times this root → this English word"},"total_root_occurrences":{"type":"integer","description":"Total occurrences of this root across all renderings"},"pct_of_root":{"type":"integer","description":"What % of this root's occurrences are rendered as this word"},"forms":{"type":"array","items":{"type":"object","properties":{"form":{"type":"string"},"count":{"type":"integer"}}}},"rendering_spectrum":{"type":"array","items":{"$ref":"#/components/schemas/SpectrumEntry"}},"examples":{"type":"array","items":{"type":"object","properties":{"work":{"type":"string"},"para":{"type":"integer"},"form":{"type":"string"},"rendering":{"type":"string"}}}}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"key_prefix":{"type":"string","example":"ctai_abc1"},"name":{"type":"string"},"created_at":{"type":"string"},"last_used":{"type":"string","nullable":true},"revoked":{"type":"boolean"}}}}}}