{
"openapi": "3.1.0",
"info": {
  "title": "Openctl Platform API",
  "version": "1.0.0",
  "description": "Openctl Platform APIs: LiveTranslate, Indexing, Search, Embeddings, Text, Web, QR, PDF, Short Links. Auth: 'Authorization: Bearer <key>' or 'X-API-Key: <key>'. Get a free key via POST /v1/keys."
},
"servers": [{"url": "https://api.openctl.com"}],
"components": {
  "securitySchemes": {"ApiKeyAuth": {"type": "http", "scheme": "bearer"}}
},
"security": [{"ApiKeyAuth": []}],
"paths": {
  "/healthz": {"get": {"security": [], "summary": "Liveness probe", "responses": {"200": {"description": "ok"}}}},
  "/v1/status": {"get": {"security": [], "summary": "Service status incl. engines", "responses": {"200": {"description": "status"}}}},
  "/v1/keys": {"post": {"security": [], "summary": "Create a free API key (self-serve)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object",
      "properties": {"name": {"type": "string"}, "owner_email": {"type": "string"}}}}}},
    "responses": {"200": {"description": "key created — the full key is shown once"}, "429": {"description": "creation rate limited"}}}},
  "/v1/keys/me": {"get": {"summary": "Current key info + monthly usage", "responses": {"200": {"description": "key"}}}},
  "/v1/account": {"get": {"summary": "Current account: plan, limits, usage", "responses": {"200": {"description": "account"}}}},
  "/v1/account/keys": {"get": {"summary": "List your API keys", "responses": {"200": {"description": "keys"}}}},
  "/v1/account/keys/{keyID}": {"delete": {"summary": "Revoke one of your keys",
    "parameters": [{"name": "keyID", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "revoked"}}}},
  "/v1/billing/plans": {"get": {"security": [], "summary": "Plan catalog (free/pro/max5/max20)", "responses": {"200": {"description": "plans"}}}},
  "/v1/billing/whop/activate": {"post": {"summary": "Activate a whop.com license key",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["license_key"], "properties": {"license_key": {"type": "string"}}}}}}},
    "responses": {"200": {"description": "plan activated"}, "400": {"description": "invalid license"}}}},
  "/v1/vision/caption": {"post": {"summary": "Vision Lite: caption an image (SmolVLM2 500M)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object",
      "properties": {"image_url": {"type": "string"}, "image_base64": {"type": "string"}, "prompt": {"type": "string"}}}}}}},
    "responses": {"200": {"description": "caption"}}}},
  "/v1/vision/detect": {"post": {"summary": "Live Detect: object detection (RF-DETR Nano/Small, COCO classes)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object",
      "properties": {"image_url": {"type": "string"}, "image_base64": {"type": "string"},
        "model": {"type": "string", "enum": ["live-detect", "live-detect-plus"]},
        "min_score": {"type": "number", "default": 0.5}}}}}}},
    "responses": {"200": {"description": "detections"}}}},
  "/v1/tts/models": {"get": {"summary": "TTS catalog incl. availability + plan lock", "responses": {"200": {"description": "models"}}}},
  "/v1/tts/speech": {"post": {"summary": "Text-to-speech (wav). Kokoro/MeloTTS free; Chatterbox Pro (voice cloning via 'reference' base64 audio)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["model", "text"],
      "properties": {"model": {"type": "string", "enum": ["kokoro-82m", "melotts", "chatterbox-turbo-350m", "chatterbox-multilingual-v3-500m", "chatterbox-500m"]},
        "text": {"type": "string"}, "voice": {"type": "string"}, "speed": {"type": "number"},
        "lang": {"type": "string"}, "reference": {"type": "string"}}}}}},
    "responses": {"200": {"description": "audio/wav"}, "402": {"description": "upgrade_required for pro models on free plan"}}}},
  "/v1/translate": {"post": {"summary": "Translate text (LiveTranslate engine)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object",
      "required": ["text", "target"],
      "properties": {"text": {"type": "string"}, "source": {"type": "string", "default": "auto"},
        "target": {"type": "string"}, "stream": {"type": "boolean", "default": false}}}}}},
    "responses": {"200": {"description": "translation (JSON, or SSE when stream=true)"}}}},
  "/v1/translate/detect": {"post": {"summary": "Detect language",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["text"], "properties": {"text": {"type": "string"}}}}}},
    "responses": {"200": {"description": "detected language"}}}},
  "/v1/translate/languages": {"get": {"summary": "Supported languages", "responses": {"200": {"description": "languages"}}}},
  "/v1/embeddings": {"post": {"summary": "Embed strings (multilingual bge-m3, 1024-dim)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["input"],
      "properties": {"input": {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}]}}}}}},
    "responses": {"200": {"description": "vectors"}}}},
  "/v1/indexes": {"get": {"summary": "List your indexes", "responses": {"200": {"description": "indexes"}}}},
  "/v1/index/{index}/documents": {"post": {"summary": "Upsert documents (auto-chunked + embedded)",
    "parameters": [{"name": "index", "in": "path", "required": true, "schema": {"type": "string"}}],
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["documents"],
      "properties": {"documents": {"type": "array", "items": {"type": "object", "required": ["text"],
        "properties": {"id": {"type": "string"}, "title": {"type": "string"}, "text": {"type": "string"},
          "url": {"type": "string"}, "metadata": {"type": "object"}}}}}}}}},
    "responses": {"200": {"description": "indexed chunks"}}}},
  "/v1/index/{index}/documents/{docID}": {"get": {"summary": "Get document chunks",
    "parameters": [{"name": "index", "in": "path", "required": true, "schema": {"type": "string"}},
      {"name": "docID", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "chunks"}, "404": {"description": "not found"}}},
    "delete": {"summary": "Delete a document",
    "parameters": [{"name": "index", "in": "path", "required": true, "schema": {"type": "string"}},
      {"name": "docID", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "deleted"}}}},
  "/v1/index/{index}/stats": {"get": {"summary": "Index statistics",
    "parameters": [{"name": "index", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "stats"}}}},
  "/v1/index/{index}": {"delete": {"summary": "Drop an entire index",
    "parameters": [{"name": "index", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "dropped"}}}},
  "/v1/search": {"post": {"summary": "Hybrid keyword + semantic search over an index",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["index", "query"],
      "properties": {"index": {"type": "string"}, "query": {"type": "string"},
        "mode": {"type": "string", "enum": ["hybrid", "keyword", "semantic"], "default": "hybrid"},
        "top_k": {"type": "integer", "default": 8}, "filter": {"type": "object"}}}}}},
    "responses": {"200": {"description": "ranked results"}}}},
  "/v1/text/detect-language": {"post": {"summary": "Detect language (lingua)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["text"], "properties": {"text": {"type": "string"}}}}}},
    "responses": {"200": {"description": "detected"}}}},
  "/v1/text/analyze": {"post": {"summary": "Language, sentiment, keywords, readability, stats",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["text"], "properties": {"text": {"type": "string"}, "keywords": {"type": "integer", "default": 10}}}}}},
    "responses": {"200": {"description": "analysis"}}}},
  "/v1/text/summarize": {"post": {"summary": "Extractive summary",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["text"], "properties": {"text": {"type": "string"}, "max_sentences": {"type": "integer", "default": 5}}}}}},
    "responses": {"200": {"description": "summary"}}}},
  "/v1/web/metadata": {"post": {"summary": "Fetch a URL and return metadata (OG, canonical, favicon…)",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["url"], "properties": {"url": {"type": "string"}}}}}},
    "responses": {"200": {"description": "metadata"}}}},
  "/v1/web/extract": {"post": {"summary": "Fetch a URL and extract readable text",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["url"], "properties": {"url": {"type": "string"}, "max_chars": {"type": "integer", "default": 20000}}}}}},
    "responses": {"200": {"description": "text + metadata"}}}},
  "/v1/qr": {"get": {"summary": "QR code (PNG or SVG)", "security": [],
    "parameters": [{"name": "data", "in": "query", "required": true, "schema": {"type": "string"}},
      {"name": "format", "in": "query", "schema": {"type": "string", "enum": ["png", "svg"], "default": "png"}},
      {"name": "scale", "in": "query", "schema": {"type": "integer", "default": 4}}],
    "responses": {"200": {"description": "image"}}}},
  "/v1/pdf/extract": {"post": {"summary": "Extract text from a PDF (multipart 'file' or raw body)",
    "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary"}}}}}},
    "responses": {"200": {"description": "pages + text"}}}},
  "/v1/links": {"post": {"summary": "Create a short link",
    "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["url"],
      "properties": {"url": {"type": "string"}, "slug": {"type": "string"}, "title": {"type": "string"}}}}}},
    "responses": {"200": {"description": "link"}, "409": {"description": "slug taken"}}}},
  "/v1/links/{slug}": {"delete": {"summary": "Delete a short link",
    "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "deleted"}}}},
  "/v1/admin/keys": {"get": {"summary": "List all keys (master only)", "responses": {"200": {"description": "keys"}}}},
  "/v1/admin/keys/{id}": {"patch": {"summary": "Update a key: tier/active/limits (master only)",
    "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}],
    "requestBody": {"content": {"application/json": {"schema": {"type": "object",
      "properties": {"tier": {"type": "string"}, "active": {"type": "boolean"}, "rpm_limit": {"type": "integer"}, "monthly_quota": {"type": "integer"}}}}}},
    "responses": {"200": {"description": "updated"}}},
    "delete": {"summary": "Revoke a key (master only)",
    "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}],
    "responses": {"200": {"description": "revoked"}}}},
  "/v1/admin/usage": {"get": {"summary": "Usage aggregates (master only)", "responses": {"200": {"description": "usage"}}}}
}
}
