openapi: 3.0.3 info: title: Brainfish Public Agents API description: "The Brainfish API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.\n\nUse the Brainfish API to programmatically manage your knowledge base, generate AI-powered answers, and integrate Brainfish capabilities into your applications.\n\n---\n\n## Just Getting Started?\n\nCheck out our [Help documentation](https://help.brainfi.sh) for guides and tutorials.\n\n---\n\n## Base URL\n\n```\nhttps://api.brainfi.sh\n```\n\nAll API requests must be made over HTTPS. Calls made over plain HTTP will fail.\n\n---\n\n## Authentication\n\nThe Brainfish API uses API tokens to authenticate requests. You can view and manage your API tokens in your [Brainfish Dashboard](https://app.brainfi.sh) under **Settings → API Tokens**.\n\nAPI tokens have the prefix `bf_api_`. Your API tokens carry many privileges, so be sure to keep them secure! Do not share your API tokens in publicly accessible areas such as GitHub, client-side code, and so forth.\n\nAll API requests must include authentication. Requests without authentication will fail.\n\n| Header | Description |\n|--------|-------------|\n| `Authorization` | Bearer token authentication: `Bearer bf_api_xxxxx` |\n| `agent-key` | Required for AI Agent endpoints only. Find this in your Agents page. |\n\n**Example: Authenticated Request**\n\n```bash\ncurl https://api.brainfi.sh/v1/auth/validate \\\n -X POST \\\n -H \"Authorization: Bearer bf_api_xxxxx\" \\\n -H \"Content-Type: application/json\"\n```\n\n---\n\n## Errors\n\nBrainfish uses conventional HTTP response codes to indicate the success or failure of an API request.\n\n| Code | Description |\n|------|-------------|\n| `2xx` | Success — The request was successful. |\n| `4xx` | Client Error — The request failed due to client-side issues (e.g., missing required parameter, invalid authentication, resource not found). |\n| `5xx` | Server Error — Something went wrong on Brainfish's servers (these are rare). |\n\n**Error Response Format**\n\n```json\n{\n \"error\": \"validation_failed\",\n \"message\": \"Request validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"query\",\n \"message\": \"Query cannot be empty\",\n \"code\": \"invalid_string\"\n }\n ],\n \"timestamp\": \"2024-01-15T10:30:00Z\",\n \"requestId\": \"req-abc123\"\n}\n```\n\nThe `requestId` can be provided to Brainfish support when troubleshooting issues.\n\n---\n\n## Rate Limiting\n\nThe API implements rate limiting to ensure fair usage and system stability.\n\n| Endpoint Type | Limit |\n|---------------|-------|\n| Most endpoints | 25 requests per minute |\n| Token revocation | 10 requests per hour |\n\nWhen you exceed the rate limit, the API returns a `429 Too Many Requests` response with headers indicating when you can retry:\n\n- `X-RateLimit-Limit`: Maximum requests allowed in the window\n- `X-RateLimit-Remaining`: Remaining requests in current window\n- `X-RateLimit-Reset`: Unix timestamp when the rate limit resets\n\n---\n\n## Available Resources\n\n| Resource | Description |\n|----------|-------------|\n| **Authentication** | Validate and revoke API tokens |\n| **AI Agents** | Generate streaming AI-powered answers from your knowledge base |\n| **Analytics** | Query conversation thread analytics with filtering and pagination |\n| **Conversations** | Generate follow-up questions for conversations |\n| **Collections** | Organize documents into collections |\n| **Catalogs** | Create catalogs and sync content via API |\n| **Documents** | Create, read, update, and delete documents |\n\n---\n\n## Quick Start\n\n**1. Create an API token** in your Brainfish dashboard under Settings → API Tokens.\n\n**2. Validate your token** to ensure it's working:\n\n```bash\ncurl https://api.brainfi.sh/v1/auth/validate \\\n -X POST \\\n -H \"Authorization: Bearer bf_api_xxxxx\" \\\n -H \"Content-Type: application/json\"\n```\n\n**3. For AI endpoints**, get your agent key from the Agents page.\n\n**4. Generate an AI answer**:\n\n```bash\ncurl https://api.brainfi.sh/v1/agents/answer \\\n -X POST \\\n -H \"Authorization: Bearer bf_api_xxxxx\" \\\n -H \"agent-key: your-agent-key\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"How do I reset my password?\"}'\n```\n\n---\n\n## Pagination\n\nList endpoints support pagination using `limit` and `offset` parameters:\n\n| Parameter | Description | Default |\n|-----------|-------------|---------|\n| `limit` | Maximum number of results to return (1-100) | 25 |\n| `offset` | Number of results to skip | 0 |\n\nPaginated responses include a `pagination` object:\n\n```json\n{\n \"data\": [...],\n \"pagination\": {\n \"offset\": 0,\n \"limit\": 25,\n \"total\": 42\n }\n}\n```\n" version: 1.0.0 contact: name: Brainfish API Support email: support@brainfish.ai url: https://help.brainfi.sh/articles/api-reference-7mjzVCAmeM license: name: Proprietary servers: - url: https://api.brainfi.sh description: Production server tags: - name: Agents description: AI agent operations for answer generation and streaming paths: /v1/agents/answer: post: summary: Generate streaming answer description: "Generate streaming answers for queries using AI agents. This endpoint provides real-time\nstreaming responses for question answering with optional user personalization.\n\nSimply provide a query string and optionally a `filter.collectionIds` array to get an AI-generated answer.\nWhen `filter.collectionIds` is provided, those collections are included in the search scope, along with\nany widget-based personalization collections when applicable. Otherwise, the endpoint uses the default\nanswer flow. The response is streamed using Server-Sent Events (SSE) format, allowing clients to receive\npartial results as they are generated.\n\n## Personalization\n\nPass the optional `user` object to enable personalized answers. When provided, the external\nuser record is upserted and their attributes are used to filter knowledge base collections\nand tailor responses. At least one of `userId`, `email`, or `phone` is required within the\n`user` object.\n\n## Streaming vs Non-Streaming\n\nSet `stream` to `false` to receive the full answer as a single JSON response instead of SSE\nevents. Defaults to `true`.\n\n## Streaming Example\n\n```javascript\nconst response = await fetch('https://api.brainfi.sh/v1/agents/answer', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer bf_api_xxxxx',\n 'agent-key': 'your-agent-key'\n },\n body: JSON.stringify({\n query: 'How do I reset my password?',\n user: { email: 'jane@example.com', properties: { plan: 'enterprise' } }\n })\n});\n\nconst reader = response.body.getReader();\nconst decoder = new TextDecoder();\n\nwhile (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value);\n const lines = chunk.split('\\n');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const event = JSON.parse(line.slice(6));\n\n switch (event.type) {\n case 'start':\n console.log('Answer started:', event.id);\n break;\n case 'progress':\n console.log('Progress:', event.content);\n break;\n case 'content':\n console.log('Content chunk:', event.content);\n break;\n case 'end':\n console.log('Answer completed:', event.conversationId);\n break;\n }\n }\n }\n}\n```\n" operationId: generateAnswer tags: - Agents security: - BearerAuth: [] AgentKey: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AnswerRequest' examples: simpleQuery: summary: Simple question value: query: How to reset my password? followupQuery: summary: Follow-up question with conversation context value: query: What if I forgot my email too? conversationId: 01234567890123456789012345 withPersonalization: summary: Personalized answer with user attributes value: query: What features are available on my plan? user: email: john@acme.com properties: plan: enterprise region: us-east withCollectionFilter: summary: Answer scoped to selected collections value: query: How do I reset my password? filter: collectionIds: - collection-uuid-1 nonStreaming: summary: Non-streaming response value: query: What are the pricing plans available? stream: false responses: '200': description: Streaming response with answer generation events content: text/event-stream: schema: type: string description: Server-sent events stream containing answer generation progress examples: streamingResponse: summary: Example streaming response for password reset query value: 'data: {"type":"start","id":"answer-abc123","conversationId":"01234567890123456789012345"} data: {"type":"progress","content":"Searching knowledge base for password reset information..."} data: {"type":"content","content":"To reset your password:\n\n1. Go to the login page at"} data: {"type":"content","content":" https://app.brainfi.sh/login\n2. Click the \"Forgot Password?\" link"} data: {"type":"content","content":"\n3. Enter your email address\n4. Check your email for reset instructions"} data: {"type":"content","content":"\n\nIf you don''t receive the email within 5 minutes, check your spam folder or contact support."} data: {"type":"end","id":"answer-abc123","conversationId":"01234567890123456789012345","complete":true} ' shortResponse: summary: Example streaming response for simple query value: 'data: {"type":"start","id":"answer-def456"} data: {"type":"content","content":"Our pricing plans include:\n\n**Starter**: $29/month - Up to 1,000 queries\n**Professional**: $99/month - Up to 10,000 queries\n**Enterprise**: Custom pricing - Unlimited queries\n\nAll plans include 24/7 support and API access."} data: {"type":"end","id":"answer-def456","complete":true} ' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/UnprocessableEntity' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' components: responses: Unauthorized: description: Authentication required or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' examples: missingToken: summary: Missing authentication token value: error: authentication_required message: 'Authentication required. Use Authorization: Bearer header' timestamp: '2024-01-15T10:30:00Z' requestId: req-abc123 missingAgentKey: summary: Missing agent key value: error: authentication_required message: Agent key is required timestamp: '2024-01-15T10:30:00Z' requestId: req-def456 invalidCredentials: summary: Invalid credentials value: error: authentication_required message: Invalid or missing authentication credentials timestamp: '2024-01-15T10:30:00Z' requestId: req-ghi789 TooManyRequests: description: Rate limit exceeded headers: X-RateLimit-Limit: schema: type: integer description: Request limit per time window X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Time when rate limit resets (Unix timestamp) content: application/json: schema: $ref: '#/components/schemas/Error' example: error: rate_limit_exceeded message: 'Too many requests. Rate limit: 25 requests per minute' timestamp: '2024-01-15T10:30:00Z' UnprocessableEntity: description: Invalid request format or unknown message type content: application/json: schema: $ref: '#/components/schemas/ValidationError' examples: emptyQuery: summary: Empty query validation error value: error: validation_failed message: Request validation failed validationErrors: - field: query message: Query cannot be empty code: invalid_string timestamp: '2024-01-15T10:30:00Z' requestId: req-val123 invalidConversationId: summary: Invalid conversation ID format value: error: validation_failed message: Request validation failed validationErrors: - field: conversationId message: Invalid conversation ID format code: invalid_string timestamp: '2024-01-15T10:30:00Z' requestId: req-val456 queryTooLong: summary: Query exceeds maximum length value: error: validation_failed message: Request validation failed validationErrors: - field: query message: Query must be 2000 characters or less code: too_big timestamp: '2024-01-15T10:30:00Z' requestId: req-val789 InternalServerError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' example: error: internal_error message: An unexpected error occurred requestId: req-abc123 timestamp: '2024-01-15T10:30:00Z' schemas: AnswerRequest: type: object required: - query properties: query: type: string description: The query string to generate an answer for minLength: 1 maxLength: 2000 example: How to reset my password? conversationId: type: string description: 'Optional conversation ID for maintaining context across multiple queries. This should be omitted for the first request and then provided in subsequent requests using the conversationId returned from the previous response. ' pattern: ^[0-9a-z]{25}$ example: 01234567890123456789012345 stream: type: boolean default: true description: 'Whether to stream the response via Server-Sent Events (SSE). When `true` (default), the response is streamed as SSE events. When `false`, the full answer is returned as a single JSON response. ' user: type: object description: 'Optional external user identification for personalization. When provided, the user record is upserted and their attributes are used to filter collections and tailor answers. At least one of `userId`, `email`, or `phone` is required within this object. ' properties: userId: type: string description: External user ID from your system email: type: string format: email description: User email address phone: type: string description: User phone number firstName: type: string description: User first name lastName: type: string description: User last name properties: type: object additionalProperties: true description: Custom key-value properties for personalization (e.g. plan, region) filter: type: object description: Optional collection filter for this public endpoint. properties: collectionIds: type: array items: type: string format: uuid description: Collection IDs to include in the answer search scope. channelType: type: string enum: - email - whatsapp - slack - msteams description: Optional channel type for context attachments: type: array maxItems: 10 items: type: object required: - type - url properties: type: type: string enum: - image url: type: string format: uri description: Optional image attachments (max 10) Error: type: object required: - error - message properties: error: type: string description: Error type or code message: type: string description: Human-readable error message details: type: object additionalProperties: true description: Additional error details timestamp: type: string format: date-time description: Error timestamp requestId: type: string description: Unique request identifier for debugging ValidationError: allOf: - $ref: '#/components/schemas/Error' - type: object properties: validationErrors: type: array items: type: object properties: field: type: string description: Field that failed validation message: type: string description: Validation error message code: type: string description: Validation error code securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: API Token description: 'Bearer token authentication. Include your API token in the Authorization header. Example: `Authorization: Bearer bf_api_xxxxx` Create tokens in your Brainfish dashboard under Settings → API Tokens. ' AccessToken: type: apiKey in: header name: access-token description: '**Deprecated**: Use Bearer authentication instead. Legacy access token header for backward compatibility. Must start with `bf_api_`. Create tokens in your Brainfish dashboard under Settings → API Tokens. ' AgentKey: type: apiKey in: header name: agent-key description: 'Agent key identifier that specifies which AI agent/widget to use for the request. Find agent keys in your Brainfish dashboard under Agents. Click on any agent key to copy it. '