{
 "openapi": "3.0.3",
 "info": {
  "title": "Tuatara Topics",
  "version": "1.0",
  "description": "Topic discovery for a set of documents, in one call. Send 4 to 2,000 documents and the number of topics you want (2 to 100): the answer is every topic's words, a short label, a description and a weight, plus each document's topic mixture. Or send one document to place it on the general topic set. A dictionary model's word knowledge guides a probabilistic topic model, so topics are coherent on small corpora and short texts; nothing is trained on or kept from requests (zero data retention). Measured on 20 Newsgroups at K=50 with the FASTopic preprocessing, five seeds, every run's topic words and document mixtures published: https://cymetica.com/benchmarks#tuatara-topics-1.0",
  "contact": {
   "name": "Cymetica",
   "url": "https://cymetica.com",
   "email": "contact@cymetica.com"
  },
  "termsOfService": "https://cymetica.com/terms",
  "license": {
   "name": "Proprietary"
  }
 },
 "servers": [
  {
   "url": "https://cymetica.com/api/v1/topics/v1",
   "description": "Production (Japan)"
  }
 ],
 "security": [
  {
   "apiKey": []
  },
  {
   "bearer": []
  }
 ],
 "tags": [
  {
   "name": "Topics",
   "description": "Find topics in documents, or place a document on the general topics"
  },
  {
   "name": "Account",
   "description": "Models, usage, health"
  }
 ],
 "paths": {
  "/topics": {
   "post": {
    "tags": [
     "Topics"
    ],
    "operationId": "topics",
    "summary": "Find the topics in a set of documents (or place one document)",
    "description": "Send `documents` (4 to 2,000 strings) with `num_topics` to fit topics on them, or `document` (one string) to place it on the general topic set. `num_words` sets the words per topic.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TopicsRequest"
       },
       "example": {
        "documents": [
         "Rates held steady as inflation cooled.",
         "The central bank left rates unchanged.",
         "New GPU chips doubled training throughput.",
         "A chip maker unveiled faster accelerators.",
         "Bond yields fell after the rate decision.",
         "The accelerator market is growing fast."
        ],
        "num_topics": 2,
        "num_words": 5
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The topics and each document's mixture",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TopicsResponse"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "402": {
      "$ref": "#/components/responses/Error"
     },
     "422": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/chat/completions": {
   "post": {
    "tags": [
     "Topics"
    ],
    "operationId": "chatCompletions",
    "summary": "The same request as a chat message (OpenAI-compatible)",
    "description": "The last user message is the request: a JSON object with `documents` or `document`, or plain text taken as one document to place. The reply content is the JSON answer; `stream: true` sends it as server-sent events.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ChatRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Chat completion whose content is the topics JSON",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "422": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/models": {
   "get": {
    "tags": [
     "Account"
    ],
    "operationId": "listModels",
    "summary": "Models, prices and limits",
    "security": [],
    "responses": {
     "200": {
      "description": "Model list",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/usage": {
   "get": {
    "tags": [
     "Account"
    ],
    "operationId": "usage",
    "summary": "Requests and tokens used by this key",
    "parameters": [
     {
      "name": "days",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 30,
       "minimum": 1,
       "maximum": 90
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Usage by day",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/health": {
   "get": {
    "tags": [
     "Account"
    ],
    "operationId": "health",
    "summary": "Service status and uptime",
    "security": [],
    "responses": {
     "200": {
      "description": "Status",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "model": {
           "type": "string"
          },
          "served": {
           "type": "boolean"
          },
          "zero_data_retention": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearer": {
    "type": "http",
    "scheme": "bearer",
    "description": "Authorization: Bearer <key>"
   },
   "apiKey": {
    "type": "apiKey",
    "in": "header",
    "name": "X-Api-Key"
   }
  },
  "responses": {
   "Error": {
    "description": "Error",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "RateLimited": {
    "description": "More than the key's requests a minute (300 by default); retry after the Retry-After seconds",
    "headers": {
     "Retry-After": {
      "schema": {
       "type": "integer"
      }
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  },
  "schemas": {
   "TopicsRequest": {
    "type": "object",
    "properties": {
     "documents": {
      "type": "array",
      "items": {
       "type": "string",
       "maxLength": 20000
      },
      "minItems": 4,
      "maxItems": 2000,
      "description": "The documents to find topics in (fit). Each up to 20,000 characters."
     },
     "document": {
      "type": "string",
      "maxLength": 20000,
      "description": "One document to place on the served topic sets (infer): general (Wikipedia-scale) and finance (markets, companies, the economy)."
     },
     "topic_set": {
      "type": "string",
      "enum": [
       "auto",
       "general",
       "finance"
      ],
      "default": "auto",
      "description": "Which served set places the document; auto answers with the set that takes it most confidently."
     },
     "num_topics": {
      "type": "integer",
      "minimum": 2,
      "maximum": 100,
      "default": 10,
      "description": "Topics to find; at most half the number of documents."
     },
     "num_words": {
      "type": "integer",
      "minimum": 3,
      "maximum": 30,
      "default": 15,
      "description": "Words per topic."
     },
     "labels": {
      "type": "boolean",
      "default": true,
      "description": "Give each topic a short label and description."
     },
     "model": {
      "type": "string",
      "default": "tuatara-topics-latest"
     }
    }
   },
   "Topic": {
    "type": "object",
    "properties": {
     "words": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "label": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "weight": {
      "type": "number",
      "description": "share of the corpus on this topic"
     }
    }
   },
   "TopicsResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "object": {
      "type": "string",
      "enum": [
       "topics"
      ]
     },
     "created": {
      "type": "integer"
     },
     "model": {
      "type": "string"
     },
     "mode": {
      "type": "string",
      "enum": [
       "fit",
       "infer"
      ]
     },
     "topics": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Topic"
      }
     },
     "documents": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "index": {
         "type": "integer"
        },
        "mixture": {
         "type": "array",
         "items": {
          "type": "object",
          "properties": {
           "topic": {
            "type": "integer"
           },
           "weight": {
            "type": "number"
           }
          }
         }
        },
        "confidence": {
         "type": "number",
         "description": "The top topic's weight (infer): how much of the document this set explains."
        },
        "on_topic_set": {
         "type": "boolean",
         "description": "False when no topic takes at least the floor of the mixture: the document is about something the set does not cover (infer)."
        }
       }
      }
     },
     "usage": {
      "type": "object",
      "properties": {
       "input_tokens": {
        "type": "integer"
       },
       "output_tokens": {
        "type": "integer"
       }
      }
     },
     "topic_set": {
      "type": "object",
      "description": "Infer only: the set that placed the document.",
      "properties": {
       "name": {
        "type": "string"
       },
       "corpus": {
        "type": "string"
       },
       "topics": {
        "type": "integer"
       },
       "floor": {
        "type": "number"
       },
       "candidates": {
        "type": "object",
        "additionalProperties": {
         "type": "number"
        },
        "description": "Every set considered and its confidence."
       },
       "note": {
        "type": "string"
       }
      }
     }
    }
   },
   "ChatRequest": {
    "type": "object",
    "required": [
     "messages"
    ],
    "properties": {
     "model": {
      "type": "string",
      "default": "tuatara-topics-latest"
     },
     "messages": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "role": {
         "type": "string"
        },
        "content": {
         "type": "string"
        }
       }
      }
     },
     "num_topics": {
      "type": "integer"
     },
     "num_words": {
      "type": "integer"
     },
     "labels": {
      "type": "boolean"
     },
     "stream": {
      "type": "boolean",
      "default": false
     }
    }
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string"
       },
       "message": {
        "type": "string"
       }
      }
     }
    }
   }
  }
 }
}
