openapi: 3.1.0
info:
  title: Hindsight API
  description: |
    Integrate Hindsight competitive intelligence, win-loss insights, and deal data into your applications.
    
    ## Authentication
    All API requests require a Bearer token in the Authorization header:
    ```
    Authorization: Bearer YOUR_API_KEY
    ```
    
    Get your API key from the [Hindsight dashboard](https://app.usehindsight.com/settings/keys).
    Newly created API keys begin with `hs_`; existing keys remain supported until they
    are rotated or expire.
    
    ## Rate Limits
    
    Hindsight applies both organization-wide and per-API-key request limits. Per-key
    defaults are approximately one-third of the organization plan limit, with a minimum
    of 5 requests per minute. Expensive operations may also consume separate usage quotas.
    On `429 Too Many Requests`, use `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and
    `X-RateLimit-Reset` (Unix milliseconds). These public headers represent the active
    response limit; separate per-key response headers are not currently provided.
  version: 1.0.0
  contact:
    name: Hindsight Support
    url: https://usehindsight.com/support
    email: support@hindsight.com

servers:
  - url: https://app.usehindsight.com/api/v1
    description: Production server

security:
  - bearerAuth: []

tags:
  - name: Chat
    description: AI-powered chat completions with competitive intelligence
  - name: Deals
    description: Access and export deal data
  - name: Documents
    description: Upload and manage documents
  - name: Interviews
    description: Create and manage win-loss interview requests
  - name: Tools
    description: Structured Hindsight tool calls for application-controlled workflows

paths:
  /tools/select-deal:
    post:
      operationId: selectDeal
      summary: Filter and list analyzed deals
      description: Returns lean, paginated deal rows for triage. Use `get-deal` to retrieve the full details for returned deal IDs.
      tags:
        - Tools
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SelectDealRequest'
      responses:
        '200':
          description: Matching deal rows
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SelectDealResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /tools/get-deal:
    post:
      operationId: getDeal
      summary: Get full details for known deal IDs
      description: Retrieves the summary and per-competitor positioning for one to ten deal IDs.
      tags:
        - Tools
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetDealRequest'
      responses:
        '200':
          description: Detailed deal records
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetDealResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /responses:
    post:
      operationId: createResponse
      summary: Create a response
      description: |
        Send a message and receive an AI-generated response with citations from your competitive intelligence data.
        Hindsight automatically orchestrates multiple searches across deals, competitors, and knowledge base to provide comprehensive answers.
      tags:
        - Chat
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
            examples:
              basic:
                summary: Basic question
                value:
                  messages:
                    - role: user
                      content: "What security objections have we encountered with Enterprise customers?"
                  stream: false
              withHistory:
                summary: With conversation history
                value:
                  messages:
                    - role: user
                      content: "What are common objections to our enterprise tier?"
                    - role: assistant
                      content: "Based on recent deals, the main objections are..."
                    - role: user
                      content: "How should we handle the pricing objection?"
                  stream: false
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatCompletionResponse'
            text/event-stream:
              schema:
                type: string
                description: Server-Sent Events stream for streaming responses
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /product-intelligence:
    get:
      operationId: getProductIntelligence
      summary: Export product-feature intelligence
      description: Returns one row per product-feature association with its raw influence summary, feature taxonomy, deal, and account context. Without filters, returns associations of every sentiment.
      tags:
        - Deals
      parameters:
        - name: date_from
          in: query
          schema:
            type: string
            format: date-time
          description: Inclusive ISO 8601 lower bound for the association creation timestamp.
        - name: date_to
          in: query
          schema:
            type: string
            format: date-time
          description: Inclusive ISO 8601 upper bound for the association creation timestamp.
        - name: sentiment
          in: query
          schema:
            type: string
            enum: [positive, negative, neutral]
          description: Filter association sentiment. Omit to return all sentiments.
        - name: tags
          in: query
          schema:
            type: string
          description: Comma-separated tags, or repeat the parameter. All specified tags must match.
        - name: product
          in: query
          schema:
            type: string
          description: Exact feature product.
        - name: product_area
          in: query
          schema:
            type: string
          description: Exact feature product area.
      responses:
        '200':
          description: Product-feature associations and applied filters.
          content:
            application/json:
              schema:
                type: object
                required: [data, meta]
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        created_at:
                          type: string
                          format: date-time
                        deal_id:
                          type: string
                        feature_id:
                          type: string
                        influence_summary:
                          type: string
                          nullable: true
                        sentiment:
                          type: boolean
                          nullable: true
                        tags:
                          type: array
                          items:
                            type: string
                        features:
                          type: object
                        deals:
                          type: object
                  meta:
                    type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /deals:
    get:
      operationId: getDeals
      summary: Get deals with filtering and pagination
      description: |
        Retrieve deals with flexible filtering, sorting, and pagination.
        Returns deal objects with all their properties and relationships.
        Use this for real-time data access and integrations.
      tags:
        - Deals
      parameters:
        - name: page_size
          in: query
          schema:
            type: integer
            default: 50
            maximum: 100
          description: Number of deals per page
        - name: page_index
          in: query
          schema:
            type: integer
            default: 0
          description: Zero-based page index
        - name: count
          in: query
          schema:
            type: boolean
          description: If true, returns only the total count
        - name: sort
          in: query
          schema:
            type: string
            enum: [created_at, updated_at, close_date, amount, name]
          description: Column to sort by
        - name: sort_order
          in: query
          schema:
            type: string
            enum: [asc, desc]
            default: desc
          description: Sort direction
        - name: columns
          in: query
          schema:
            type: string
          description: Comma-separated list of columns to return
        - name: searchQuery
          in: query
          schema:
            type: string
          description: Fuzzy search across deal names
        - name: status
          in: query
          schema:
            type: string
          description: JSON array of deal stages
        - name: owner_ids
          in: query
          schema:
            type: string
          description: JSON array of owner IDs
        - name: close_date
          in: query
          schema:
            type: string
          description: "JSON object: {\"from\": \"2026-01-01\", \"to\": \"2026-03-31\"}"
        - name: amount
          in: query
          schema:
            type: string
          description: "JSON object: {\"min\": 10000, \"max\": 100000}"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    items:
                      $ref: '#/components/schemas/Deal'
                  - type: integer
                    description: Total count when count=true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /deals/export:
    post:
      operationId: exportDeals
      summary: Bulk export deals to CSV
      description: |
        Generate a CSV file of deal data with flexible filtering and column selection.
        Returns an export_id to track the job status and download the file when ready.
      tags:
        - Deals
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExportDealsRequest'
      responses:
        '200':
          description: Export job started
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportDealsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'
    
  /deals/export/{export_id}:
    get:
      operationId: getExportStatus
      summary: Get export status
      description: |
        Check the status of a bulk export job and get the download URL when ready.
      tags:
        - Deals
      parameters:
        - name: export_id
          in: path
          required: true
          schema:
            type: string
          description: Export ID from the initial export request
      responses:
        '200':
          description: Export status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportStatusResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Export not found
        '500':
          $ref: '#/components/responses/InternalServerError'

  /documents/library:
    post:
      operationId: uploadLibraryDocument
      summary: Upload document to knowledge base
      description: |
        Upload competitive intelligence documents, assets, and other files to your library.
        Documents are automatically processed, chunked, and indexed for search.
      tags:
        - Documents
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/LibraryDocumentUploadRequest'
            examples:
              withUrl:
                summary: Upload from URL
                value:
                  file_name: "Competitor X Pricing Guide.pdf"
                  file_url: "https://example.com/document.pdf"
                  content_type: "application/pdf"
                  type: "asset"
                  competitor_id: "comp_123"
                  source: "drive"
              withFile:
                summary: Upload binary file
                value:
                  file_name: "Battlecard.md"
                  file: "<binary file content>"
                  content_type: "text/markdown"
                  type: "asset"
                  competitor_name: "Competitor X"
                  source: "notion"
      responses:
        '200':
          description: Document upload initiated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentUploadResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /deals/documents:
    post:
      operationId: uploadDealDocument
      summary: Upload document to a deal
      description: |
        Associate documents with specific deals for win-loss analysis.
        Audio and video files are automatically transcribed.
        Documents are processed and used to enrich deal insights.
      tags:
        - Documents
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DealDocumentUploadRequest'
            examples:
              withDealId:
                summary: Upload with Hindsight deal ID
                value:
                  file_name: "Discovery Call Notes.pdf"
                  file_url: "https://example.com/document.pdf"
                  content_type: "application/pdf"
                  deal_id: "deal_123"
                  source: "gong"
              withSalesforceId:
                summary: Upload with Salesforce ID
                value:
                  file_name: "Call Recording.mp3"
                  file_url: "https://example.com/recording.mp3"
                  content_type: "audio/mpeg"
                  salesforce_id: "006xxxxxxxxxxxx"
                  source: "gong"
              withHubspotId:
                summary: Upload with HubSpot ID
                value:
                  file_name: "Email Thread.eml"
                  file: "<binary file content>"
                  content_type: "message/rfc822"
                  hubspot_id: "12345678"
                  source: "Hubspot"
      responses:
        '200':
          description: Document upload initiated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentUploadResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Deal not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: "not_found"
                  message: "Deal with the specified ID was not found"
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /interviews:
    post:
      operationId: createInterview
      summary: Create an interview request
      description: |
        Creates an interview request. Buyer requests upsert the contact by email. When a `sequence_id`
        is provided, the buyer contact is enrolled in the sequence and Hindsight's scheduling agent handles
        outreach automatically. When only `interview_type_id` is provided, the request is created and the
        survey link is returned without any outreach. Set `respondent_type` to `seller` to create an internal,
        link-only seller request with no contact creation, email, Slack, or sequence outreach.
      tags:
        - Interviews
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInterviewRequest'
            examples:
              withSequence:
                summary: Enroll in a sequence (with outreach)
                value:
                  contact_email: "jane@acme.com"
                  contact_name: "Jane Smith"
                  contact_context:
                    title: "VP of Engineering"
                    company: "Acme Corp"
                    use_case: "Evaluating us for CI/CD pipeline automation"
                  sequence_id: "seq_abc123"
                  deal_id: "deal_xyz789"
              linkOnly:
                summary: Create survey link only (no outreach)
                value:
                  contact_email: "jane@acme.com"
                  contact_name: "Jane Smith"
                  interview_type_id: "type_abc123"
                  objective: "Understand why we lost this deal to Competitor X"
              salesforceSeller:
                summary: Create an internal seller debrief for a synced Salesforce opportunity
                value:
                  contact_email: "alex.rep@acme.com"
                  contact_name: "Alex Rep"
                  interview_type_id: "seller_debrief_type_abc123"
                  salesforce_opportunity_id: "006xx000001ABCdAAO"
                  respondent_type: "seller"
                  objective: "Capture the seller perspective on this closed deal"
      responses:
        '201':
          description: Interview request created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateInterviewResponse'
              example:
                interview_request_id: 4821
                contact_id: "contact_abc123"
                deal_id: "deal_xyz789"
                salesforce_opportunity_id: null
                respondent_type: "buyer"
                survey_url: "https://app.usehindsight.com/survey?token=tok_xyz"
                survey_token: "tok_xyz"
                status: "sent"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /interviews/{id}:
    get:
      operationId: getInterview
      summary: Get interview status and transcript
      description: |
        Returns the current status of an interview request and, once completed, its full transcript.

        Poll this endpoint to check whether a contact has completed their interview.
        When `status` is `"completed"`, the `transcript` field contains the full conversation content.
      tags:
        - Interviews
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
          description: The `interview_request_id` returned when the interview was created.
          example: 4821
      responses:
        '200':
          description: Interview request found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetInterviewResponse'
              examples:
                pending:
                  summary: Interview sent, awaiting response
                  value:
                    interview_request_id: 4821
                    contact_id: "contact_abc123"
                    deal_id: "deal_xyz789"
                    survey_url: "https://app.usehindsight.com/survey?token=tok_xyz"
                    status: "sent"
                    objective: "Understand why we lost to Competitor X"
                    email_sent_at: "2026-05-15T10:00:00Z"
                    created_at: "2026-05-15T09:00:00Z"
                    transcript: null
                completed:
                  summary: Interview completed
                  value:
                    interview_request_id: 4821
                    contact_id: "contact_abc123"
                    deal_id: "deal_xyz789"
                    survey_url: "https://app.usehindsight.com/survey?token=tok_xyz"
                    status: "completed"
                    objective: "Understand why we lost to Competitor X"
                    email_sent_at: "2026-05-15T10:00:00Z"
                    created_at: "2026-05-15T09:00:00Z"
                    transcript:
                      document_id: "doc_abc123"
                      content: "**Paige:** Thanks for taking the time today...\n\n**Jane:** Happy to help..."
                      created_at: "2026-05-16T14:30:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Interview request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: "not_found"
                  message: "Interview request not found"
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'
    patch:
      operationId: updateInterview
      summary: Update an interview request
      description: |
        Updates context on an existing interview request. Accepts any combination of
        `contact_context`, `contact_name`, and `objective`. At least one field must be provided.

        - `contact_context` and `contact_name` update the contact record associated with the request.
          Context is stored in the contact's notes field and used by Paige in every future interview prompt for that contact.
        - `objective` updates the interview-specific goal on the request itself.
      tags:
        - Interviews
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
          description: The `interview_request_id` returned when the interview was created.
          example: 4821
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateInterviewRequest'
            examples:
              updateContext:
                summary: Update contact context
                value:
                  contact_context:
                    title: "CTO"
                    evaluation_notes: "Completed POC, main concern is pricing"
              updateObjective:
                summary: Update interview objective
                value:
                  objective: "Focus on why pricing was a blocker vs. Competitor X"
              updateAll:
                summary: Update everything
                value:
                  contact_name: "Jane Smith"
                  contact_context:
                    title: "CTO"
                    evaluation_notes: "Completed POC"
                  objective: "Focus on pricing concerns"
      responses:
        '200':
          description: Interview request updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateInterviewResponse'
              example:
                interview_request_id: 4821
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Interview request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: "not_found"
                  message: "Interview request not found"
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: "API key from Hindsight Settings → API keys. Use `Authorization: Bearer YOUR_API_KEY`. Newly created keys begin with `hs_`; existing keys remain supported until rotated or expired."

  schemas:
    SelectDealRequest:
      type: object
      properties:
        query:
          type: string
          nullable: true
          description: Fuzzy deal or client-name match. Cannot be used with semantic_query or segment_id.
        semantic_query:
          type: string
          nullable: true
          description: Conceptual search over deal content. Cannot be used with query or segment_id.
        segment_id:
          type: string
          nullable: true
          description: Segment ID. Cannot be used with query.
        competitor_id:
          type: string
          nullable: true
        deal_stage:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
          nullable: true
          description: One or more deal-stage names.
        amount:
          type: object
          nullable: true
          properties:
            min:
              type: number
              nullable: true
            max:
              type: number
              nullable: true
        close_date:
          type: object
          nullable: true
          properties:
            from:
              type: string
              nullable: true
            to:
              type: string
              nullable: true
        type:
          type: string
          nullable: true
        region:
          type: string
          nullable: true
        owner_name:
          type: string
          nullable: true
          description: Owner name, email, or `me`, `my`, or `mine`.
        limit:
          type: integer
          minimum: 1
          maximum: 50
          default: 20
        page:
          type: integer
          minimum: 1
          default: 1

    GetDealRequest:
      type: object
      required: [deal_ids]
      properties:
        deal_ids:
          type: array
          minItems: 1
          maxItems: 10
          items:
            type: string

    DealToolRow:
      type: object
      properties:
        type:
          type: string
          example: deal
        id:
          type: string
          nullable: true
        deal_id:
          type: string
          nullable: true
        name:
          type: string
          nullable: true
        client_name:
          type: string
          nullable: true
        stage:
          type: string
          nullable: true
        amount:
          type: number
          nullable: true
        close_date:
          type: string
          nullable: true
        url:
          type: string
          nullable: true

    SelectDealResponse:
      type: object
      properties:
        total_returned:
          type: integer
        limit_applied:
          type: integer
          nullable: true
        page:
          type: integer
        page_size:
          type: integer
        has_more:
          type: boolean
        next_page:
          type: integer
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/DealToolRow'

    GetDealResponse:
      type: object
      properties:
        total_returned:
          type: integer
        limit_applied:
          type: integer
          nullable: true
        results:
          type: array
          items:
            allOf:
              - $ref: '#/components/schemas/DealToolRow'
              - type: object
                properties:
                  summary:
                    type: string
                    nullable: true
                  competitors:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                          nullable: true
                        positioning_summary:
                          type: string
                          nullable: true
                        key_differentiators:
                          type: string
                          nullable: true

    ChatCompletionRequest:
      type: object
      required:
        - messages
      properties:
        messages:
          type: array
          description: The conversation messages
          items:
            $ref: '#/components/schemas/Message'
          minItems: 1
        stream:
          type: boolean
          description: Whether to stream the response using Server-Sent Events
          default: false

    Message:
      type: object
      required:
        - role
        - content
      properties:
        role:
          type: string
          enum: [user, assistant, system]
          description: The role of the message author
        content:
          type: string
          description: The content of the message

    ChatCompletionResponse:
      type: object
      properties:
        message:
          type: object
          properties:
            role:
              type: string
              enum: [assistant]
            content:
              type: string
              description: The AI-generated response with inline citations
            citations:
              type: array
              description: Source documents referenced in the response
              items:
                $ref: '#/components/schemas/Citation'
        tool_calls:
          type: array
          description: The internal tools that were called to generate the response
          items:
            type: string
          example: ["search_across_deals", "search_deal_documents"]

    Citation:
      type: object
      properties:
        document_id:
          type: string
          description: Unique identifier for the source document
        document_name:
          type: string
          description: Name of the source document
        deal_id:
          type: string
          nullable: true
          description: Associated deal ID, if applicable
        deal_name:
          type: string
          nullable: true
          description: Associated deal name, if applicable
        url:
          type: string
          format: uri
          description: URL to view the document in Hindsight
          example: "https://app.usehindsight.com/deals/deal_123/documents/viewer/doc_abc123"
        excerpt:
          type: string
          description: Relevant excerpt from the document

    Deal:
      type: object
      properties:
        id:
          type: string
          description: Hindsight deal ID
          example: "deal_123"
        name:
          type: string
          description: Deal name
          example: "Acme Corp - Enterprise License"
        amount:
          type: number
          description: Deal value
          example: 50000
        status_id:
          type: string
          description: Current deal stage ID
          example: "negotiation"
        previous_status_id:
          type: string
          nullable: true
          description: Previous deal stage ID
          example: "qualification"
        close_date:
          type: string
          format: date
          description: "Expected or actual close date (internal field name: proposal_due)"
          example: "2026-03-15"
        created_at:
          type: string
          format: date-time
          description: Deal creation timestamp
        owner_id:
          type: string
          description: Deal owner ID
        salesforce_id:
          type: string
          nullable: true
          description: Salesforce Opportunity ID
        hubspot_id:
          type: string
          nullable: true
          description: HubSpot Deal ID
        deal_analyzed:
          type: boolean
          description: Whether deal has been analyzed
        analysis_verified:
          type: boolean
          description: Whether analysis has been verified
        type:
          type: string
          nullable: true
          description: Type of deal
          example: "New Business"
        region:
          type: string
          nullable: true
          description: Geographic region
        deal_competitor_associations:
          type: array
          items:
            type: object
            properties:
              competitor_id:
                type: string
              is_primary:
                type: boolean
              is_incumbent:
                type: boolean
          description: Array of competitor associations
        drivers:
          type: array
          items:
            type: object
            properties:
              reason_id:
                type: string
              positive:
                type: boolean
                nullable: true
              summary:
                type: string
          description: Array of deal drivers/reasons
        wl_product_fit_score:
          type: number
          nullable: true
          description: Product fit score (1-5)
        wl_sales_execution_score:
          type: number
          nullable: true
          description: Sales execution score (1-5)
        wl_relationship_score:
          type: number
          nullable: true
          description: Relationship score (1-5)

    ExportDealsRequest:
      type: object
      required:
        - columns
      properties:
        columns:
          type: array
          items:
            type: string
          description: Array of column IDs to include in the export
          example: ["name", "amount", "stage", "close_date"]
        filters:
          type: object
          description: Optional filters to apply
          properties:
            deal_ids:
              type: array
              items:
                type: string
              description: Specific deal IDs to export
            owner_ids:
              type: array
              items:
                type: string
              description: Filter by owner IDs
            status:
              type: array
              items:
                type: string
              description: Filter by deal stages
            close_date:
              type: object
              properties:
                from:
                  type: string
                  format: date
                to:
                  type: string
                  format: date
            amount:
              type: object
              properties:
                min:
                  type: number
                max:
                  type: number
            competitor_ids:
              type: array
              items:
                type: string
            deal_type:
              type: array
              items:
                type: string
            region:
              type: array
              items:
                type: string
            industry:
              type: array
              items:
                type: string
            analyzed:
              type: boolean
            verified:
              type: boolean

    ExportDealsResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        export_id:
          type: string
          description: Unique export job ID
          example: "exp_abc123"
        status:
          type: string
          enum: [pending]
          description: Initial status is always pending
        message:
          type: string
          example: "Export job started successfully"
        estimated_completion:
          type: string
          example: "2-3 minutes"

    ExportStatusResponse:
      type: object
      properties:
        export_id:
          type: string
          example: "exp_abc123"
        status:
          type: string
          enum: [pending, completed, failed]
          description: Current export status
        download_url:
          type: string
          format: uri
          nullable: true
          description: Download URL (available when status is completed)
        rows_exported:
          type: integer
          nullable: true
          description: Number of rows in the export
        error:
          type: string
          nullable: true
          description: Error message if status is failed
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
        failed_at:
          type: string
          format: date-time
          nullable: true
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the download URL expires (7 days after completion)

    LibraryDocumentUploadRequest:
      type: object
      required:
        - file_name
        - content_type
        - type
      properties:
        file_name:
          type: string
          description: Name of the file
          example: "Competitor X Pricing Guide.pdf"
        file_url:
          type: string
          format: uri
          description: URL to download the file from (provide either file_url or file)
          example: "https://example.com/document.pdf"
        file:
          type: string
          format: binary
          description: Binary file content (provide either file or file_url)
        content_type:
          type: string
          description: MIME type of the file
          example: "application/pdf"
          enum:
            - application/pdf
            - text/markdown
            - text/plain
            - application/vnd.openxmlformats-officedocument.wordprocessingml.document
            - application/vnd.openxmlformats-officedocument.presentationml.presentation
            - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
        type:
          type: string
          description: Document type
          enum:
            - asset
            - intel
        competitor_id:
          type: string
          description: Hindsight competitor ID (provide either competitor_id or competitor_name)
          example: "comp_123"
        competitor_name:
          type: string
          description: Competitor name - will be resolved to competitor_id automatically
          example: "Competitor X"
        source:
          type: string
          description: Source application where the document originated
          enum:
            - drive
            - notion
            - confluence
            - onedrive
            - sharepoint
            - vanta
            - url
            - zapier
            - api
          example: "drive"
    DealDocumentUploadRequest:
      type: object
      required:
        - file_name
        - content_type
      properties:
        file_name:
          type: string
          description: Name of the file
          example: "Discovery Call Notes.pdf"
        file_url:
          type: string
          format: uri
          description: URL to download the file from (provide either file_url or file)
        file:
          type: string
          format: binary
          description: Binary file content (provide either file or file_url)
        content_type:
          type: string
          description: MIME type of the file
          example: "application/pdf"
        deal_id:
          type: string
          description: Hindsight deal ID (provide one of deal_id, salesforce_id, or hubspot_id)
          example: "deal_123"
        salesforce_id:
          type: string
          description: Salesforce Opportunity ID
          example: "006xxxxxxxxxxxx"
        hubspot_id:
          type: string
          description: HubSpot Deal ID
          example: "12345678"
        source:
          type: string
          description: Source application where the document originated
          enum:
            - gong
            - clari
            - fathom
            - fireflies
            - avoma
            - outreach
            - gmail
            - Salesforce
            - Hubspot
            - api
          example: "gong"

    DocumentUploadResponse:
      type: object
      properties:
        document:
          type: object
          properties:
            id:
              type: string
              description: Unique identifier for the document
              example: "doc_abc123"
            file_name:
              type: string
              description: Name of the uploaded file
              example: "Competitor X Pricing Guide.pdf"
            status:
              type: string
              description: Processing status of the document
              enum:
                - processing
                - ready
                - failed
              example: "processing"
            type:
              type: string
              description: Document type
              enum:
                - asset
                - intel
              example: "asset"
            url:
              type: string
              format: uri
              description: URL to view the document in Hindsight
              example: "https://app.usehindsight.com/deals/deal_123/documents/viewer/doc_abc123"
            created_at:
              type: string
              format: date-time
              description: Timestamp when the document was created
              example: "2026-02-10T12:00:00Z"
        run_id:
          type: string
          description: ID to track the document processing run
          example: "run_xyz789"

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Error code
              example: "unauthorized"
            message:
              type: string
              description: Human-readable error message
              example: "Invalid API key"
            details:
              type: object
              description: Additional error details
              additionalProperties: true

    GetInterviewResponse:
      type: object
      properties:
        interview_request_id:
          type: integer
          description: ID of the interview request.
          example: 4821
        contact_id:
          type: string
          nullable: true
          description: ID of the contact being interviewed.
          example: "contact_abc123"
        deal_id:
          type: string
          nullable: true
          description: Associated deal ID, or null.
          example: "deal_xyz789"
        survey_url:
          type: string
          nullable: true
          description: Direct link to the survey for this contact.
          example: "https://app.usehindsight.com/survey?token=tok_xyz"
        status:
          type: string
          enum: [created, sent, completed]
          description: |
            `created` — request exists, no email sent yet.
            `sent` — email sent, awaiting the contact's response.
            `completed` — interview finished; `transcript` is populated.
          example: "sent"
        objective:
          type: string
          nullable: true
          description: The interview-specific goal, if set.
          example: "Understand why we lost to Competitor X"
        email_sent_at:
          type: string
          format: date-time
          nullable: true
          description: ISO timestamp when the outreach email was sent, or null.
          example: "2026-05-15T10:00:00Z"
        created_at:
          type: string
          format: date-time
          description: ISO timestamp when the interview request was created.
          example: "2026-05-15T09:00:00Z"
        transcript:
          nullable: true
          description: Present when `status` is `"completed"`, null otherwise.
          type: object
          properties:
            document_id:
              type: string
              description: ID of the document storing the transcript.
              example: "doc_abc123"
            content:
              type: string
              description: Full interview transcript in markdown format.
              example: "**Paige:** Thanks for taking the time today...\n\n**Jane:** Happy to help..."
            created_at:
              type: string
              format: date-time
              description: ISO timestamp when the transcript was saved.
              example: "2026-05-16T14:30:00Z"

    UpdateInterviewRequest:
      type: object
      properties:
        contact_context:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: |
            Updated context about the contact. Overwrites the existing contact notes.
            Used by Paige as background in every future interview prompt for this contact.
          example:
            title: "CTO"
            evaluation_notes: "Completed 30-day POC, main concern is pricing"
        contact_name:
          type: string
          description: Updated display name for the contact.
          example: "Jane Smith"
        objective:
          type: string
          description: Updated goal for this specific interview.
          example: "Focus on why pricing was a blocker vs. Competitor X"

    UpdateInterviewResponse:
      type: object
      properties:
        interview_request_id:
          type: integer
          description: ID of the updated interview request.
          example: 4821

    CreateInterviewRequest:
      type: object
      required: []
      properties:
        contact_email:
          type: string
          format: email
          description: Email address of the person to interview. Required. Buyer contacts are upserted; seller requests use this as the internal respondent.
          example: "jane@acme.com"
        contact_name:
          type: string
          description: Full name of the person to interview. Used to create or update a buyer contact record.
          example: "Jane Smith"
        contact_context:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: |
            Unstructured context about a buyer contact — passed to Paige as background information when
            conducting the interview. Can be a plain string or a JSON object; objects are serialized automatically.
            Stored in the buyer contact's notes field and included in every interview prompt for that contact.
          example:
            title: "VP of Engineering"
            use_case: "Evaluating us for CI/CD pipeline automation"
            evaluation_stage: "POC completed"
        interview_type_id:
          type: string
          description: |
            ID of the interview type to use (e.g. win-loss buyer, NPS). Required if `sequence_id` is not provided.
            Find interview type IDs in your Hindsight dashboard under Settings → Interview Types.
          example: "type_abc123"
        sequence_id:
          type: string
          description: |
            ID of an outreach sequence. When provided, the contact is enrolled in the sequence and
            Hindsight's scheduling agent handles email delivery automatically. The interview type is
            inherited from the sequence. Required if `interview_type_id` is not provided.
          example: "seq_abc123"
        deal_id:
          type: string
          description: |
            Hindsight deal ID to associate this interview with. The deal must belong to your organization.
            Mutually exclusive with `salesforce_opportunity_id`.
          example: "deal_xyz789"
        salesforce_opportunity_id:
          type: string
          description: |
            Salesforce Opportunity ID for an already-synced deal. Hindsight resolves it using the
            organization-scoped `deals.salesforce_id` field. Mutually exclusive with `deal_id`.
          example: "006xx000001ABCdAAO"
        respondent_type:
          type: string
          enum: [buyer, seller]
          default: buyer
          description: |
            Audience for the interview. `buyer` upserts an external contact and supports sequences.
            `seller` creates an internal, link-only request and cannot be used with `sequence_id`.
        objective:
          type: string
          description: |
            Custom goal for this specific interview. Paige uses this as additional context when
            conducting the interview (e.g. "Understand why we lost to Competitor X on pricing").
          example: "Understand why we lost this deal to Competitor X"

    CreateInterviewResponse:
      type: object
      properties:
        interview_request_id:
          type: integer
          description: ID of the created interview request.
          example: 4821
        contact_id:
          type: string
          nullable: true
          description: ID of the upserted buyer contact record, or null for seller requests.
          example: "contact_abc123"
        deal_id:
          type: string
          nullable: true
          description: Resolved Hindsight deal ID, or null.
          example: "deal_xyz789"
        salesforce_opportunity_id:
          type: string
          nullable: true
          description: Salesforce Opportunity ID used to resolve the deal, or null.
          example: "006xx000001ABCdAAO"
        respondent_type:
          type: string
          enum: [buyer, seller]
          description: Audience for the created interview request.
          example: "buyer"
        survey_url:
          type: string
          nullable: true
          description: Direct link to the survey for this contact. Share this link manually if not using a sequence.
          example: "https://app.usehindsight.com/survey?token=tok_xyz"
        survey_token:
          type: string
          nullable: true
          description: Raw token used in the survey URL.
          example: "tok_xyz"
        status:
          type: string
          enum: [created, sent]
          description: |
            `created` — interview request created, no outreach sent (link-only path).
            `sent` — contact enrolled in sequence, outreach queued.
          example: "sent"

  responses:
    BadRequest:
      description: Bad request - invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "bad_request"
              message: "Invalid parameters"
              details:
                missing_fields: ["file_name"]

    Unauthorized:
      description: Unauthorized - invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "unauthorized"
              message: "Invalid API key"

    Forbidden:
      description: Forbidden - the API key's role cannot use this tool
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "forbidden"
              message: "Your role (member) does not have permission to perform this action."

    InsufficientScope:
      description: Forbidden - the API key is not scoped for this action
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "insufficient_scope"
              message: "This API key is not scoped for this action."
              required_scopes: ["documents:write"]

    RateLimitExceeded:
      description: Too many requests - rate limit or applicable usage quota exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "rate_limit_exceeded"
              message: "Rate limit exceeded. Please retry after the reset time in the response headers."
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Requests allowed in the current 60-second window.
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Requests remaining in the current 60-second window.
        X-RateLimit-Reset:
          schema:
            type: integer
            format: int64
          description: Unix timestamp in milliseconds when the rate-limit window resets.
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "internal_error"
              message: "An unexpected error occurred"
