openapi: 3.1.0
info:
  title: Fluent API
  version: 1.0.0
  summary: Run Fluent agents and access connected data.
  description: |
    The public Fluent API powers the CLI and customer integrations.
    Most successful responses wrap their payload in a data property. Errors
    contain detail and status properties without that envelope.
servers:
  - url: https://www.fluenterp.com
    description: Production
tags:
  - name: Discovery
    description: Find the API, its scopes, and its policies without a credential.
  - name: Agents
    description: Discover agents and prepare their input files.
  - name: Runs
    description: Start and monitor asynchronous agent runs.
  - name: Documents
    description: Read, process, and delete documents produced by agents.
  - name: Connections
    description: Discover connected systems and read their records.
  - name: Databases
    description: Discover queryable databases and schemas.
  - name: Tables
    description: Read records from a queryable table.
  - name: Queries
    description: Run queries against accessible databases.
  - name: Utilities
    description: Search the web and manage conversation resources.
  - name: MCP
    x-group: Model Context Protocol
    description: Connect an external MCP client to an agent's tools.
security:
  - ApiKey: []
  - BearerCredential: []
paths:
  /api/v1:
    get:
      tags: [Discovery]
      operationId: getApiIndex
      summary: Get the API index
      description: |
        Returns the public, unauthenticated index of the API: the base URL,
        supported authentication methods and OAuth scopes, the rate-limit and
        deprecation conventions, and links to the documentation and this
        specification. Use it to discover the current surface without a
        credential.
      security: []
      responses:
        "200":
          description: API index
          headers:
            RateLimit-Limit:
              description: Requests allowed in the current window.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiIndex"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/agents:
    get:
      tags: [Agents]
      operationId: listAgents
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["agents:read"]
      summary: List agents
      description: |
        Returns the agents visible to the authenticated user, ordered by name.
        OAuth tokens require the agents:read scope.
      responses:
        "200":
          description: Accessible agents
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentsEnvelope"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/agents/{agent_id}/upload-urls:
    post:
      tags: [Agents]
      operationId: createAgentUploadUrls
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:write"]
      summary: Create file upload URLs
      description: |
        Creates one presigned URL per file. Upload each file directly with PUT
        and the same Content-Type before creating a run. URLs expire after one
        hour. OAuth tokens require the runs:write scope.
      parameters:
        - $ref: "#/components/parameters/AgentId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UploadUrlsRequest"
            examples:
              invoice:
                value:
                  files:
                    - file_name: invoice.pdf
                      content_type: application/pdf
      responses:
        "200":
          description: Presigned upload URLs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadUrlsEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/agents/{agent_id}/run:
    post:
      tags: [Runs]
      operationId: createAgentRun
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:write"]
      summary: Create an agent run
      description: |
        Starts an asynchronous run with uploaded files, a user message, or both.
        OAuth tokens require the runs:write scope. In addition to the credential
        limit, this operation is limited to 30 requests per 60 seconds per agent.
      parameters:
        - $ref: "#/components/parameters/AgentId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRunRequest"
            examples:
              document:
                value:
                  files:
                    - file_key: agents/example/invoice.pdf
                      file_name: invoice.pdf
                      content_type: application/pdf
                  process_together: false
              text:
                value:
                  files: []
                  user_message: Summarize our open issues
      responses:
        "200":
          description: Run queued
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateRunEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/runs:
    get:
      tags: [Runs]
      operationId: listRuns
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:read"]
      summary: List agent runs
      description: |
        Lists API-originated runs in reverse chronological order. List items do
        not include documents or conversation IDs. OAuth tokens require the
        runs:read scope.
      parameters:
        - name: agent_id
          in: query
          description: Restrict results to one agent.
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          description: Restrict results to one run status.
          schema:
            $ref: "#/components/schemas/RunStatus"
        - name: limit
          in: query
          description: Maximum number of runs to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: offset
          in: query
          description: Number of matching runs to skip.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Paginated run summaries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RunsListEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/runs/{id}:
    get:
      tags: [Runs]
      operationId: getRun
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:read"]
      summary: Get an agent run
      description: |
        Returns durable run status, conversations, and documents. A failed run
        can still contain documents and conversation IDs. OAuth tokens require
        the runs:read scope.
      parameters:
        - $ref: "#/components/parameters/RunId"
      responses:
        "200":
          description: Run details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RunEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/documents/{id}:
    get:
      tags: [Documents]
      operationId: getDocument
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:read"]
      summary: Get a document
      description: |
        Returns a document and its full document_data payload. OAuth tokens
        require the runs:read scope.
      parameters:
        - $ref: "#/components/parameters/DocumentId"
      responses:
        "200":
          description: Document details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      tags: [Documents]
      operationId: processDocument
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:write"]
      summary: Process a document
      description: |
        Processes the document's current data into its configured system of
        record. An external-system rejection is returned as an updated document
        with status error and HTTP 200. OAuth tokens require runs:write.
      parameters:
        - $ref: "#/components/parameters/DocumentId"
      responses:
        "200":
          description: Updated document
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "429":
          $ref: "#/components/responses/RateLimited"
    delete:
      tags: [Documents]
      operationId: deleteDocument
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:write"]
      summary: Delete a document
      description: |
        Cancels in-flight work and moves the document to trash. This is a soft
        delete. OAuth tokens require the runs:write scope.
      parameters:
        - $ref: "#/components/parameters/DocumentId"
      responses:
        "200":
          description: Document moved to trash
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteDocumentEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/connections:
    get:
      tags: [Connections]
      operationId: listConnections
      summary: List connections
      description: |
        Lists connections visible to the API-key user. This legacy operation
        returns a top-level array instead of a data envelope.
      parameters:
        - $ref: "#/components/parameters/Offset"
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            default: 100
          description: Maximum number of connections to return.
      responses:
        "200":
          description: Connections
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Connection"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/connections/{connection_id}/entities:
    get:
      tags: [Connections]
      operationId: listConnectionEntities
      summary: List connection entities
      description: |
        Lists the entities exposed by a connection. This legacy operation
        returns a top-level array instead of a data envelope.
      parameters:
        - $ref: "#/components/parameters/ConnectionId"
        - $ref: "#/components/parameters/Offset"
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1000
          description: Maximum number of entities to return.
      responses:
        "200":
          description: Connection entities
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ConnectionEntity"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/connections/{connection_id}/records:
    get:
      tags: [Connections]
      operationId: listConnectionRecords
      summary: List connection records
      description: |
        Reads records from one connection entity. Record shape and filter syntax
        depend on the connection. This legacy operation returns a top-level array.
      parameters:
        - $ref: "#/components/parameters/ConnectionId"
        - $ref: "#/components/parameters/StableEgress"
        - name: entity_id
          in: query
          required: true
          description: Entity identifier returned by the entities operation.
          schema:
            type: string
        - $ref: "#/components/parameters/Offset"
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          description: Maximum number of records to return.
        - name: filter
          in: query
          description: JSON-encoded filter understood by the connection.
          schema:
            type: string
          example: '{"status":"open"}'
      responses:
        "200":
          description: Connection records
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FlexibleRecord"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
    patch:
      tags: [Connections]
      operationId: updateConnectionRecord
      summary: Update a connection record
      description: |
        Updates a single row by key. Only supported for connection types that
        allow writes (currently SQL Server); other connection types return 400.
      parameters:
        - $ref: "#/components/parameters/ConnectionId"
        - $ref: "#/components/parameters/StableEgress"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [entity, key_column, key_value, values]
              properties:
                entity:
                  type: string
                  description: Table to update, as "schema.table".
                key_column:
                  type: string
                  description: Column identifying the row to update.
                key_value:
                  oneOf:
                    - type: string
                    - type: number
                  description: Value of key_column for the target row.
                values:
                  type: object
                  additionalProperties:
                    oneOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - type: "null"
                  description: Column/value pairs to set.
            examples:
              resetStatus:
                value:
                  entity: dbo.IDEAS_ISSUEMTL
                  key_column: RegNum
                  key_value: 127
                  values:
                    ProcStatus: 0
      responses:
        "200":
          description: Rows affected
          content:
            application/json:
              schema:
                type: object
                properties:
                  rows_affected:
                    type: integer
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      tags: [Connections]
      operationId: insertConnectionRecord
      summary: Insert a connection record
      description: |
        Inserts a single new row. Only supported for connection types that
        allow writes (currently SQL Server); other connection types return 400.
      parameters:
        - $ref: "#/components/parameters/ConnectionId"
        - $ref: "#/components/parameters/StableEgress"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [entity, values]
              properties:
                entity:
                  type: string
                  description: Table to insert into, as "schema.table".
                values:
                  type: object
                  additionalProperties:
                    oneOf:
                      - type: string
                      - type: number
                      - type: boolean
                      - type: "null"
                  description: Column/value pairs for the new row.
            examples:
              scheduleEntry:
                value:
                  entity: dbo.IDEAS_PROGRAMACION
                  values:
                    JobNum: "000021"
                    ProdQty: 100
      responses:
        "201":
          description: Rows affected
          content:
            application/json:
              schema:
                type: object
                properties:
                  rows_affected:
                    type: integer
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/databases:
    get:
      tags: [Databases]
      operationId: listDatabases
      summary: List databases
      description: Lists queryable databases visible to the API-key user.
      responses:
        "200":
          description: Databases
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DatabasesEnvelope"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/databases/{id}/tables:
    get:
      tags: [Databases]
      operationId: listDatabaseTables
      summary: List database tables
      description: Lists the queryable tables in one accessible database.
      parameters:
        - $ref: "#/components/parameters/DatabaseId"
      responses:
        "200":
          description: Database tables
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TablesEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/databases/{id}/schema:
    get:
      tags: [Databases]
      operationId: getDatabaseSchema
      summary: Get a database schema
      description: Returns table and column metadata for an accessible database.
      parameters:
        - $ref: "#/components/parameters/DatabaseId"
      responses:
        "200":
          description: Database schema
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DatabaseSchemaEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/tables/{id}:
    get:
      tags: [Tables]
      operationId: listTableRecords
      summary: List table records
      description: |
        Reads records from a queryable table. The operation has an additional
        limit of 5 requests per 60 seconds per user.
      parameters:
        - $ref: "#/components/parameters/TableId"
        - $ref: "#/components/parameters/Offset"
        - name: limit
          in: query
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 5000
            default: 100
        - name: order_by
          in: query
          description: Column used to order results.
          schema:
            type: [string, "null"]
        - name: order_direction
          in: query
          description: Sort direction when order_by is present.
          schema:
            type: string
            enum: [asc, desc]
            default: asc
        - name: incremental_value
          in: query
          description: |
            When order_by is also present, return rows whose order column is
            greater than this value.
          schema:
            type: [string, "null"]
      responses:
        "200":
          description: Table records
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordsEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/query:
    post:
      tags: [Queries]
      operationId: queryDatabase
      summary: Query a database
      description: |
        Executes a query against an accessible database. Queries can be
        long-running; clients should allow sufficient request time.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QueryRequest"
            example:
              database_id: db_123
              query: SELECT * FROM invoices LIMIT 10
      responses:
        "200":
          description: Query records
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordsEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/search-web:
    post:
      tags: [Utilities]
      operationId: searchWeb
      summary: Search the web
      description: Searches the web and returns a generated summary with source URLs.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [query]
              properties:
                query:
                  type: string
                  description: Search request to answer.
            example:
              query: Current steel price trends in North America
      responses:
        "200":
          description: Search summary and citations
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchWebEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/threads/{id}:
    get:
      tags: [Utilities]
      operationId: getThread
      summary: Get thread messages
      description: Returns conversation messages in their stored order.
      parameters:
        - name: id
          in: path
          required: true
          description: Conversation identifier.
          schema:
            type: string
      responses:
        "200":
          description: Ordered messages
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ThreadEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/threads/{id}/messages:
    post:
      tags: [Utilities]
      operationId: continueConversation
      summary: Continue an interactive conversation
      security:
        - ApiKey: []
        - BearerCredential: []
        - OAuth2: ["runs:write"]
      description: |
        Sends a text message using the existing conversation's agent and saved
        history. Waits for the current interactive chat turn and returns final
        versions of its emitted assistant and tool messages. Tools may launch
        background work that finishes later. Does not create a background run,
        grant approvals, or submit form answers. Requires conversation write
        access. Chat errors are returned in data.error with HTTP 200.
      parameters:
        - name: id
          in: path
          required: true
          description: Existing conversation identifier.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [message]
              properties:
                message:
                  type: string
                  minLength: 1
            example:
              message: Use the 24 inch conveyor
      responses:
        "200":
          description: Current chat turn finished
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContinueConversationEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: The conversation is already responding.
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/sandbox-snapshots:
    post:
      tags: [Utilities]
      operationId: createSandboxSnapshotUpload
      summary: Create a snapshot upload URL
      description: |
        Creates a presigned URL for uploading a sandbox snapshot and records the
        snapshot against an accessible conversation.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SnapshotUploadRequest"
            example:
              conversationId: conversation_123
              sizeBytes: 1048576
      responses:
        "200":
          description: Snapshot upload target
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SnapshotUploadEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"
    get:
      tags: [Utilities]
      operationId: getSandboxSnapshotDownload
      summary: Get a snapshot download URL
      description: Returns a presigned download URL, or null when no snapshot exists.
      parameters:
        - name: conversation_id
          in: query
          required: true
          description: Conversation whose snapshot should be restored.
          schema:
            type: string
      responses:
        "200":
          description: Snapshot download target
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SnapshotDownloadEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
  /api/v1/agents/{agent_id}/mcp:
    get:
      tags: [MCP]
      operationId: getAgentMcp
      summary: Send an MCP GET request
      description: |
        Handles a stateless Model Context Protocol Streamable HTTP GET request.
        Agent-scoped OAuth tokens and API keys are supported.
      parameters:
        - $ref: "#/components/parameters/AgentId"
      responses:
        "200":
          $ref: "#/components/responses/McpResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          description: |
            Missing or invalid credential. Missing credentials receive a
            WWW-Authenticate challenge with RFC 9728 protected-resource metadata.
          headers:
            WWW-Authenticate:
              schema:
                type: string
              description: OAuth protected-resource discovery challenge.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          $ref: "#/components/responses/NotFound"
    post:
      tags: [MCP]
      operationId: postAgentMcp
      summary: Send an MCP request
      description: |
        Handles a stateless Model Context Protocol Streamable HTTP request. The
        body is a JSON-RPC MCP message. Agent-scoped OAuth tokens and API keys
        are supported.
      parameters:
        - $ref: "#/components/parameters/AgentId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/McpRequest"
            example:
              jsonrpc: "2.0"
              id: 1
              method: tools/list
      responses:
        "200":
          $ref: "#/components/responses/McpResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          description: |
            Missing or invalid credential. Missing credentials receive a
            WWW-Authenticate challenge with RFC 9728 protected-resource metadata.
          headers:
            WWW-Authenticate:
              schema:
                type: string
              description: OAuth protected-resource discovery challenge.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags: [MCP]
      operationId: deleteAgentMcpSession
      summary: Close an MCP session
      description: |
        Acknowledges session cleanup requests. The transport is stateless, so
        there is no server-side session to remove.
      parameters:
        - $ref: "#/components/parameters/AgentId"
      responses:
        "200":
          description: Cleanup acknowledged
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: A Fluent API key beginning with fl-.
    BearerCredential:
      type: http
      scheme: bearer
      bearerFormat: Fluent API key or OAuth access token
      description: |
        A Fluent API key beginning with fl-, or an OAuth access token beginning
        with flpt_ on operations that support OAuth.
    OAuth2:
      type: oauth2
      description: |
        A Fluent OAuth access token beginning with flpt_, sent as a bearer
        credential. Tokens are granted only the scopes they request, and each
        operation below lists the scopes it requires.
      flows:
        authorizationCode:
          authorizationUrl: https://www.fluenterp.com/oauth/authorize
          tokenUrl: https://www.fluenterp.com/oauth/token
          refreshUrl: https://www.fluenterp.com/oauth/token
          scopes:
            agents:read: List the agents the credential's user can see.
            runs:read: Read agent runs and the documents they produce.
            runs:write: Upload files, create runs, process documents, and delete documents.
  parameters:
    AgentId:
      name: agent_id
      in: path
      required: true
      description: Fluent agent ID.
      schema:
        type: string
        format: uuid
    RunId:
      name: id
      in: path
      required: true
      description: Public run ID.
      schema:
        type: string
        format: uuid
    DocumentId:
      name: id
      in: path
      required: true
      description: Fluent document ID.
      schema:
        type: string
        format: uuid
    ConnectionId:
      name: connection_id
      in: path
      required: true
      description: Connection ID.
      schema:
        type: string
        format: uuid
    StableEgress:
      name: X-Fl-Egress
      in: header
      required: false
      description: |
        Optional. Set to `true` to route this request through a stable,
        allowlistable egress IP instead of the default path — needed for an
        on-premise connection (e.g. a customer's own SQL Server) whose
        firewall allowlists by IP. Same operation and response either way.
        The same `fl-*` key also works by calling this same operation
        directly at `https://api-ecs.fluenterp.com/v1/connections/{id}/records`,
        for the same stable-egress guarantee without this header.
      schema:
        type: boolean
    DatabaseId:
      name: id
      in: path
      required: true
      description: Database ID.
      schema:
        type: string
    TableId:
      name: id
      in: path
      required: true
      description: Table ID.
      schema:
        type: string
    Offset:
      name: offset
      in: query
      description: Number of records to skip.
      schema:
        type: integer
        minimum: 0
        default: 0
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing, invalid, expired, or unsupported credential
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: The credential lacks access or a required scope
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Resource not found or not visible to the caller
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Conflict:
      description: Resource state conflicts with the operation
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    RateLimited:
      description: Rate limit exceeded
      headers:
        RateLimit-Limit:
          description: Requests allowed in the current window.
          schema:
            type: integer
        RateLimit-Remaining:
          description: Requests remaining in the current window.
          schema:
            type: integer
        RateLimit-Reset:
          description: Seconds until the current window resets.
          schema:
            type: integer
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
        x-ratelimit-limit:
          description: Legacy alias of RateLimit-Limit.
          schema:
            type: integer
        x-ratelimit-remaining:
          description: Legacy alias of RateLimit-Remaining.
          schema:
            type: integer
        x-ratelimit-reset:
          description: |
            Unix timestamp (seconds) at which the current window resets. Unlike
            RateLimit-Reset, which is a delta.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    McpResponse:
      description: MCP JSON-RPC response
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/McpResponse"
  schemas:
    ApiIndex:
      type: object
      description: |
        The public index of the API, served without a credential at /api/v1.
      additionalProperties: false
      required:
        - name
        - version
        - base_url
        - documentation_url
        - developers_url
        - openapi_url
        - authentication
        - onboarding
        - rate_limits
        - versioning
        - resources
      properties:
        name:
          type: string
          description: Human-readable API name.
        description:
          type: string
          description: What the API does.
        version:
          type: string
          description: Current major version, matching the URL path segment.
        base_url:
          type: string
          format: uri
          description: Absolute base URL every operation hangs off.
        documentation_url:
          type: string
          format: uri
        openapi_url:
          type: string
          format: uri
          description: This specification.
        developers_url:
          type: string
          format: uri
        llms_txt_url:
          type: string
          format: uri
        authentication:
          type: object
          additionalProperties: false
          required: [methods]
          properties:
            methods:
              type: array
              description: Every credential type the API accepts.
              items:
                type: object
                additionalProperties: false
                required: [type, documentation_url]
                properties:
                  type:
                    type: string
                    enum: [api_key, oauth2]
                  headers:
                    type: array
                    description: Accepted header forms, for api_key.
                    items:
                      type: string
                  self_serve:
                    type: boolean
                    description: Whether a caller can issue this credential themselves.
                  credential_creation:
                    type: string
                    enum: [available_after_account_access]
                    description: When an API key can be issued.
                  account_access:
                    type: string
                    enum: [invite_required]
                    description: How a caller obtains the account needed to issue credentials.
                  flow:
                    type: string
                    description: OAuth flow, for oauth2.
                  metadata_url:
                    type: string
                    format: uri
                    description: RFC 8414 authorization-server metadata, for oauth2.
                  scopes_supported:
                    type: array
                    items:
                      type: string
                  documentation_url:
                    type: string
                    format: uri
        onboarding:
          type: object
          description: Current account-access and trial requirements.
          additionalProperties: false
          required: [account_access, access_request_url, trial, public_sandbox_available]
          properties:
            account_access:
              type: string
              enum: [invite_required]
            access_request_url:
              type: string
              format: uri
            trial:
              type: object
              additionalProperties: false
              required: [available, duration_days, invite_required]
              properties:
                available:
                  type: boolean
                duration_days:
                  type: integer
                  minimum: 1
                invite_required:
                  type: boolean
            public_sandbox_available:
              type: boolean
        rate_limits:
          type: object
          additionalProperties: false
          required: [requests, window_seconds, response_headers]
          properties:
            requests:
              type: integer
              description: Requests allowed per window.
            window_seconds:
              type: integer
            scope:
              type: string
              description: What the limit is counted against.
            response_headers:
              type: array
              items:
                type: string
            documentation_url:
              type: string
              format: uri
        versioning:
          type: object
          additionalProperties: false
          required: [strategy, current_version]
          properties:
            strategy:
              type: string
              enum: [url_path]
            current_version:
              type: string
            deprecation_headers:
              type: array
              items:
                type: string
            minimum_sunset_notice_days:
              type: integer
              description: Days between a Deprecation header appearing and its Sunset date.
            documentation_url:
              type: string
              format: uri
        resources:
          type: object
          description: Absolute URL per top-level resource, path templates included.
          additionalProperties:
            type: string
        clients:
          type: object
          additionalProperties: false
          properties:
            cli:
              type: string
              format: uri
              description: Package registry page for the official CLI.
            cli_documentation_url:
              type: string
              format: uri
        webhooks_documentation_url:
          type: string
          format: uri
    Error:
      type: object
      required: [detail]
      properties:
        detail:
          type: string
          description: Human-readable failure detail.
        status:
          type: integer
          description: HTTP status code.
      additionalProperties: true
      example:
        detail: Agent not found
        status: 404
    Agent:
      type: object
      additionalProperties: false
      required: [id, name, description]
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: [string, "null"]
    AgentsEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [agents]
          properties:
            agents:
              type: array
              items:
                $ref: "#/components/schemas/Agent"
    UploadUrlsRequest:
      type: object
      additionalProperties: false
      required: [files]
      properties:
        files:
          type: array
          minItems: 1
          maxItems: 50
          items:
            type: object
            additionalProperties: false
            required: [file_name, content_type]
            properties:
              file_name:
                type: string
                minLength: 1
              content_type:
                type: string
                minLength: 1
    Upload:
      type: object
      additionalProperties: false
      required: [file_name, file_key, upload_url]
      properties:
        file_name:
          type: string
        file_key:
          type: string
        upload_url:
          type: string
          format: uri
    UploadUrlsEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [uploads]
          properties:
            uploads:
              type: array
              items:
                $ref: "#/components/schemas/Upload"
    RunFile:
      type: object
      additionalProperties: false
      required: [file_key, file_name, content_type]
      properties:
        file_key:
          type: string
          minLength: 1
        file_name:
          type: string
          minLength: 1
        content_type:
          type: string
          minLength: 1
    BackgroundFile:
      type: object
      additionalProperties: false
      required: [file_key, file_name]
      properties:
        file_key:
          type: string
          minLength: 1
        file_name:
          type: string
          minLength: 1
    CreateRunRequest:
      type: object
      additionalProperties: false
      properties:
        files:
          type: array
          maxItems: 50
          default: []
          items:
            $ref: "#/components/schemas/RunFile"
        user_message:
          type: string
          description: Instruction or text input for the agent.
        process_together:
          type: boolean
          default: false
          description: Process foreground files in one agent conversation.
        notification_email:
          type: string
          format: email
          description: Email to notify when processing finishes.
        background_files:
          type: array
          maxItems: 10
          description: Files available to tools but not read directly by the agent.
          items:
            $ref: "#/components/schemas/BackgroundFile"
      anyOf:
        - required: [files]
          properties:
            files:
              minItems: 1
        - required: [user_message]
          properties:
            user_message:
              minLength: 1
      if:
        required: [process_together]
        properties:
          process_together:
            const: true
      then:
        properties:
          files:
            maxItems: 10
    RunStatus:
      type: string
      enum: [queued, running, completed, failed, cancelled]
    CreateRun:
      type: object
      additionalProperties: false
      required: [run_id, workflow_run_id, status, status_url, message]
      properties:
        run_id:
          type: string
          format: uuid
          description: Stable public run ID.
        workflow_run_id:
          type: string
          format: uuid
          deprecated: true
          description: Deprecated alias for run_id.
        status:
          $ref: "#/components/schemas/RunStatus"
        status_url:
          type: string
          format: uri
        message:
          type: string
    CreateRunEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/CreateRun"
    RunDocument:
      type: object
      required:
        - id
        - type
        - status
        - conversation_id
        - created_at
        - processed_at
        - error
        - trace_id
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          description: Document type reported by its data payload.
        status:
          type: string
        conversation_id:
          type: [string, "null"]
        created_at:
          type: string
          format: date-time
        processed_at:
          type: [string, "null"]
          format: date-time
        error:
          type: [string, "null"]
        trace_id:
          type: [string, "null"]
    Document:
      allOf:
        - $ref: "#/components/schemas/RunDocument"
        - type: object
          required: [document_data]
          properties:
            document_data:
              description: Type-specific structured document content.
    RunSummary:
      type: object
      required:
        - id
        - workflow_type
        - agent_id
        - agent_name
        - status
        - trace_id
        - error
        - created_at
        - started_at
        - completed_at
      properties:
        id:
          type: string
          format: uuid
        workflow_type:
          type: [string, "null"]
        agent_id:
          type: string
          format: uuid
        agent_name:
          type: [string, "null"]
        status:
          $ref: "#/components/schemas/RunStatus"
        trace_id:
          type: [string, "null"]
        error:
          type: [string, "null"]
        created_at:
          type: string
          format: date-time
        started_at:
          type: [string, "null"]
          format: date-time
        completed_at:
          type: [string, "null"]
          format: date-time
    Run:
      allOf:
        - $ref: "#/components/schemas/RunSummary"
        - type: object
          required: [conversation_ids, documents]
          properties:
            conversation_ids:
              type: array
              items:
                type: string
            documents:
              type: array
              items:
                $ref: "#/components/schemas/RunDocument"
    RunsList:
      type: object
      additionalProperties: false
      required: [runs, total, offset, limit]
      properties:
        runs:
          type: array
          items:
            $ref: "#/components/schemas/RunSummary"
        total:
          type: integer
          minimum: 0
        offset:
          type: integer
          minimum: 0
        limit:
          type: integer
          minimum: 1
    RunsListEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/RunsList"
    RunEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/Run"
    DocumentEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/Document"
    DeleteDocumentEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [id, deleted]
          properties:
            id:
              type: string
              format: uuid
            deleted:
              type: boolean
              const: true
    Connection:
      type: object
      additionalProperties: false
      required: [id, type]
      properties:
        id:
          type: string
        type:
          type: string
    ConnectionEntity:
      type: object
      required: [identifier, label]
      properties:
        identifier:
          type: string
        label:
          type: string
      additionalProperties: true
    FlexibleRecord:
      type: object
      description: Shape depends on the selected data source.
      additionalProperties: true
    Database:
      type: object
      additionalProperties: false
      required: [id, name, team_id]
      properties:
        id:
          type: string
        name:
          type: string
        team_id:
          type: string
    DatabasesEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Database"
    Table:
      type: object
      additionalProperties: false
      required: [id, name]
      properties:
        id:
          type: string
        name:
          type: string
    TablesEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Table"
    DatabaseColumn:
      type: object
      additionalProperties: false
      required: [table_name, column_name, column_type]
      properties:
        table_name:
          type: string
        column_name:
          type: string
        column_type:
          type: string
        label:
          type: string
        comment:
          type: string
        starred:
          type: boolean
    DatabaseSchemaEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DatabaseColumn"
    RecordsEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/FlexibleRecord"
    QueryRequest:
      type: object
      additionalProperties: false
      required: [database_id, query]
      properties:
        database_id:
          type: string
        query:
          type: string
    SearchWebEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [summary, citations]
          properties:
            summary:
              type: string
            citations:
              type: array
              items:
                type: object
                additionalProperties: false
                required: [url]
                properties:
                  url:
                    type: string
                    format: uri
    ThreadEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [messages]
          properties:
            messages:
              type: array
              description: Stored Fluent chat messages.
              items: {}
    ContinueConversationEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [conversation_id, messages, error]
          properties:
            conversation_id:
              type: string
            messages:
              type: array
              description: Final V3 messages emitted during this turn, including tool results and pending questions.
              items:
                type: object
                required: [version, content]
                properties:
                  version:
                    type: integer
                    enum: [3]
                  content:
                    type: object
                    additionalProperties: true
            error:
              type: string
              nullable: true
    SnapshotUploadRequest:
      type: object
      additionalProperties: false
      required: [conversationId]
      properties:
        conversationId:
          type: string
        sizeBytes:
          type: number
          minimum: 0
    SnapshotUploadEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [uploadUrl, s3Key]
          properties:
            uploadUrl:
              type: string
              format: uri
            s3Key:
              type: string
    SnapshotDownloadEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data:
          type: object
          additionalProperties: false
          required: [downloadUrl]
          properties:
            downloadUrl:
              type: [string, "null"]
              format: uri
    McpRequest:
      type: object
      required: [jsonrpc, method]
      properties:
        jsonrpc:
          type: string
          const: "2.0"
        id:
          type: [string, integer, "null"]
        method:
          type: string
        params:
          type: object
          additionalProperties: true
      additionalProperties: true
    McpResponse:
      type: object
      required: [jsonrpc]
      properties:
        jsonrpc:
          type: string
          const: "2.0"
        id:
          type: [string, integer, "null"]
        result: {}
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: integer
            message:
              type: string
            data: {}
      additionalProperties: true
