> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usehindsight.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk Export Deals

> 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.


Bulk export deal data with flexible filtering and column selection. Generates a CSV file for download that includes all specified deal fields and custom properties.

<Accordion title="Copy for AI context">
  ```text theme={null}
  POST https://app.usehindsight.com/api/v1/deals/export
  Authorization: Bearer YOUR_API_KEY
  Content-Type: application/json

  Request body:
  {
    "columns": ["name", "amount", "deal_status", "close_date", ...],  // Array of column IDs to include
    "filters": {                                                          // Optional filters
      "deal_ids": ["deal_123", "deal_456"],                              // Specific deal IDs
      "owner_ids": ["user_abc"],                                         // Deal owner IDs
      "status": ["Won", "Lost"],                                         // Deal stages (Hindsight stage values)
      "close_date": {                                                     // Date range
        "from": "2026-01-01",
        "to": "2026-03-31"
      },
      "amount": {                                                // Deal size range
        "min": 10000,
        "max": 100000
      },
      "competitors": ["comp_123"],                                       // Competitor IDs (any competitor on deal)
      "deal_type": ["New Business", "Expansion"],                        // Deal types
      "region": ["North America", "EMEA"],                               // Regions
      "industry": ["Technology", "Finance"],                             // Industries
      "product_labels": ["Product A"],                                   // Product labels
      "analyzed": true,                                                  // Only analyzed deals
      "verified": true                                                   // Only verified analyses
    }
  }

  200 Response:
  {
    "success": true,
    "export_id": "exp_abc123",
    "status": "pending",
    "message": "Export job started successfully"
  }

  GET https://app.usehindsight.com/api/v1/deals/export/{export_id}
  200 Response:
  {
    "export_id": "exp_abc123",
    "status": "completed | pending | failed",
    "download_url": "https://app.usehindsight.com/api/v1/deals/export/exp_abc123/download?token=...",  // Available when status is "completed"
    "rows_exported": 150,
    "created_at": "2026-03-10T12:00:00Z",
    "completed_at": "2026-03-10T12:02:30Z",
    "expires_at": "2026-03-17T12:02:30Z"  // Download URL expires in 7 days
  }

  Rate limits: Per-minute (10/60/300 req/min for Essentials/Growth/Enterprise) + monthly quota per route.
  ```
</Accordion>

## Overview

The bulk export API allows you to generate CSV files of your deal data with custom column selection and filtering. This is useful for:

* Creating custom reports for leadership
* Exporting data for external analysis tools
* Generating filtered deal lists for specific time periods or segments
* Backing up deal data

## Request Format

### Required Fields

| Parameter | Type      | Description                                                                                            |
| --------- | --------- | ------------------------------------------------------------------------------------------------------ |
| `columns` | string\[] | Array of column IDs to include in the export. See [Available Columns](#available-columns) for options. |

### Optional Filters

All filters are optional. If no filters are provided, all deals in your organization will be exported. These are the same canonical filter names and semantics used by GET `/deals`; export values are native JSON rather than JSON-encoded query strings.

#### Deal Identification

| Filter     | Type      | Description                                  | Example                    |
| ---------- | --------- | -------------------------------------------- | -------------------------- |
| `deal_ids` | string\[] | Export specific deals by their Hindsight IDs | `["deal_123", "deal_456"]` |

#### People & Ownership

| Filter          | Type      | Description                | Example                    |
| --------------- | --------- | -------------------------- | -------------------------- |
| `owner_ids`     | string\[] | Filter by deal owner IDs   | `["user_abc", "user_xyz"]` |
| `collaborators` | string\[] | Filter by collaborator IDs | `["user_def"]`             |

#### Deal Attributes

| Filter           | Type      | Description                                                             | Example                                    |
| ---------------- | --------- | ----------------------------------------------------------------------- | ------------------------------------------ |
| `status`         | string\[] | Deal stages. Values are your CRM's stage names (e.g. `"Won"`, `"Lost"`) |                                            |
| `deal_type`      | string\[] | Types of deals                                                          | `["New Business", "Expansion", "Renewal"]` |
| `region`         | string\[] | Geographic regions                                                      | `["North America", "EMEA", "APAC"]`        |
| `industry`       | string\[] | Customer industries                                                     | `["Technology", "Healthcare", "Finance"]`  |
| `product_labels` | string\[] | Product labels associated with the deal                                 | `["Product A", "Product B"]`               |

> **Note on status values:** `status` filters come from your your specific workspace configuration.

#### Date & Amount Filters

| Filter            | Type   | Description           | Example                                      |
| ----------------- | ------ | --------------------- | -------------------------------------------- |
| `close_date`      | object | Date range filter     | `{"from": "2026-01-01", "to": "2026-03-31"}` |
| `close_date.from` | string | Start date (ISO 8601) | `"2026-01-01"`                               |
| `close_date.to`   | string | End date (ISO 8601)   | `"2026-03-31"`                               |
| `amount`          | object | Deal amount range     | `{"min": 10000, "max": 100000}`              |
| `amount.min`      | number | Minimum deal amount   | `10000`                                      |
| `amount.max`      | number | Maximum deal amount   | `100000`                                     |

#### Competitive Intelligence

| Filter               | Type      | Description                                                                                       | Example                    |
| -------------------- | --------- | ------------------------------------------------------------------------------------------------- | -------------------------- |
| `competitors`        | string\[] | Filter by competitor IDs — matches deals where any of the specified competitors appear            | `["comp_123", "comp_456"]` |
| `primary_competitor` | string\[] | Filter by competitor IDs — matches deals where the specified competitor is the primary competitor | `["comp_123"]`             |
| `has_competitor`     | boolean   | Only deals with any competitor mentioned                                                          | `true`                     |

#### Analysis Filters

| Filter     | Type    | Description                    | Example |
| ---------- | ------- | ------------------------------ | ------- |
| `analyzed` | boolean | Only include analyzed deals    | `true`  |
| `verified` | boolean | Only include verified analyses | `true`  |

#### CRM Filters (Advanced)

| Filter                       | Type      | Description                                           | Example                         |
| ---------------------------- | --------- | ----------------------------------------------------- | ------------------------------- |
| `salesforce_filters`         | object\[] | Deal-level Salesforce properties (Opportunity object) | See [CRM Filters](#crm-filters) |
| `salesforce_filters_account` | object\[] | Account-level Salesforce properties (Account object)  | See [CRM Filters](#crm-filters) |
| `hubspot_filters`            | object\[] | Deal-level HubSpot properties                         | See [CRM Filters](#crm-filters) |
| `hubspot_filters_account`    | object\[] | Account-level HubSpot properties (Company object)     | See [CRM Filters](#crm-filters) |

### Filter Type Modifiers

For array-based filters, you can specify how they should be applied:

| Filter Type          | Description                               | Example                              |
| -------------------- | ----------------------------------------- | ------------------------------------ |
| `is` / `is any of`   | Matches if any value is present (default) | Include deals with competitor A OR B |
| `is not` / `exclude` | Excludes if any value is present          | Exclude deals with competitor A or B |
| `include all of`     | Matches only if all values are present    | Include only deals with BOTH A AND B |

To use filter modifiers, append `_filter_type` to the filter name:

```json theme={null}
{
  "competitors": ["comp_123", "comp_456"],
  "competitors_filter_type": "include all of"
}
```

Supported `_filter_type` suffixes: `owner_filter_type`, `collaborator_filter_type`, `competitors_filter_type`, `primary_competitor_filter_type`, `product_filter_type`, `status_filter_type`, `deal_type_filter_type`, `region_filter_type`, `industry_filter_type`.

Existing integrations may continue using the [legacy filter aliases documented on GET `/deals`](/api-reference/get-deals#legacy-filter-aliases).

## Available Columns

### Standard Columns

| Column ID           | Description                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| `deal_id`           | Hindsight deal ID (alias of `id`)                                           |
| `salesforce_id`     | Salesforce Opportunity ID                                                   |
| `name`              | Deal name                                                                   |
| `owner_id`          | Deal owner ID                                                               |
| `all_competitors`   | All competitors involved in the deal                                        |
| `drivers`           | Win/loss drivers and reasons                                                |
| `features`          | Product features discussed                                                  |
| `scorecard`         | Complete win-loss analysis scorecard (includes all scores and explanations) |
| `deal_status`       | Current deal stage                                                          |
| `previous_status`   | Previous deal stage                                                         |
| `amount`            | Deal value                                                                  |
| `close_date`        | Expected/actual close date (CSV header: "Close Date")                       |
| `created_at`        | Deal creation date                                                          |
| `deal_analyzed`     | Whether deal has been analyzed                                              |
| `analysis_verified` | Reserved verification field; currently returns an empty value               |
| `type`              | Deal type (New Business, Expansion, Renewal)                                |
| `region`            | Geographic region                                                           |
| `summary`           | Complete structured deal summary                                            |

> **Note:** The `scorecard` column includes all win-loss metrics (product fit, sales execution, relationship, price sensitivity, competitive intensity, customer fit, messaging fit, and messaging accuracy) with both scores and explanations.

### Dynamic Columns

These columns are generated based on your workspace configuration and CRM integrations:

#### CRM Deal Properties

Deal-level custom properties synced from your CRM (Opportunity/Deal object):

* Format: `crm_{property_id}`
* Example: `crm_lead_source`, `crm_sales_rep_region`

#### CRM Account Properties

Account-level properties synced from your CRM:

* HubSpot format: `crm_hubspot_account_{property_id}`
* Salesforce format: `crm_salesforce_account_{property_id}`
* Examples: `crm_hubspot_account_industry`, `crm_salesforce_account_annual_revenue`

#### Custom Metrics

Organization-specific metrics you've configured. Use the metric's **name** (not its internal ID) when specifying columns:

* Score format: `custom_metric_score_{metric_name}`
* Explanation format: `custom_metric_explanation_{metric_name}`
* Example: For a custom metric called "Strategic Fit": `custom_metric_score_Strategic Fit` or `custom_metric_explanation_StrategicFit`

#### Custom Answers

Custom questions you've set up for deal analysis. Use the question's **name** (not its internal ID):

* Format: `custom_answer_{answer_name}`
* Example: `custom_answer_Champion identified` or `custom_answer_ChampionIdentified` for a custom question called "Champion identified"

### Dynamic column example

The dynamic selector formats above are identical for GET `/deals` and bulk export. CRM selectors use the underlying CRM property ID; custom metrics and answers use their configured Hindsight names. Custom metric and answer name matching is case-insensitive and ignores spaces.

Only CRM properties synced into Hindsight are available. If a deal has no value for a requested CRM property, metric, or answer, its CSV cell is empty.

```bash theme={null}
curl -X POST https://app.usehindsight.com/api/v1/deals/export \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "columns": [
      "deal_id",
      "name",
      "crm_LeadSource",
      "crm_salesforce_account_Industry",
      "custom_metric_score_Strategic Fit",
      "custom_metric_explanation_Strategic Fit",
      "custom_answer_Champion identified"
    ],
    "filters": {
      "analyzed": true
    }
  }'
```

Nested values such as `summary`, `scorecard`, `drivers`, `features`, and competitor data are JSON-encoded inside their CSV cells. Dynamic CRM properties, metric scores, metric explanations, and custom answers are emitted as individual CSV columns.

## Response

### Initial Response (POST)

When you submit an export request, you'll receive an export\_id and status:

```json theme={null}
{
  "success": true,
  "export_id": "exp_abc123",
  "status": "pending",
  "message": "Export job started successfully"
}
```

### Checking Export Status (GET)

Poll the export status endpoint to check when your export is ready:

```
GET /api/v1/deals/export/{export_id}
```

Response while processing:

```json theme={null}
{
  "export_id": "exp_abc123",
  "status": "pending",
  "created_at": "2026-03-10T12:00:00Z"
}
```

Response when complete:

```json theme={null}
{
  "export_id": "exp_abc123",
  "status": "completed",
  "download_url": "https://app.usehindsight.com/api/v1/deals/export/exp_abc123/download?token=...",
  "rows_exported": 150,
  "created_at": "2026-03-10T12:00:00Z",
  "completed_at": "2026-03-10T12:02:30Z",
  "expires_at": "2026-03-17T12:02:30Z"
}
```

Response if failed:

```json theme={null}
{
  "export_id": "exp_abc123",
  "status": "failed",
  "error": "Export failed: Invalid column ID 'invalid_column'",
  "created_at": "2026-03-10T12:00:00Z",
  "failed_at": "2026-03-10T12:01:15Z"
}
```

### Download URL Expiration

* Download URLs are valid for 7 days after generation
* After expiration, you'll need to create a new export request
* The export record remains accessible via GET for 30 days

## CRM Filters

Use CRM filters to filter deals based on properties from your Salesforce or HubSpot integration. Deal-level and account-level properties use separate filter keys:

```json theme={null}
{
  "salesforce_filters_account": [
    {
      "property": { "id": "Account.Industry", "map_to": "industry" },
      "operator": "is",
      "value": "COMPUTER_SOFTWARE"
    }
  ],
  "salesforce_filters": [
    {
      "property": { "id": "Amount" },
      "operator": "is greater than",
      "value": "50000"
    }
  ]
}
```

**Deal vs. account filters:**

| Filter key                   | Object                   |
| ---------------------------- | ------------------------ |
| `salesforce_filters`         | Opportunity (deal-level) |
| `salesforce_filters_account` | Account (account-level)  |
| `hubspot_filters`            | Deal (deal-level)        |
| `hubspot_filters_account`    | Company (account-level)  |

The `property` field accepts either a string or an object:

```json theme={null}
{ "property": { "id": "field_name" } }
```

For ordinary CRM properties, the shorter string form is also accepted and is canonical:

```json theme={null}
{ "property": "field_name" }
```

Use the object form when a standard account property requires `map_to`.

**`map_to` for standard account properties:**

Some account properties (like industry or company name) are stored in a dedicated database column rather than the raw CRM payload. These require a `map_to` field pointing to the column name. Without it, the filter searches the raw CRM JSON and won't find data for these fields.

```json theme={null}
{
  "property": {
    "id": "Account.Industry",
    "map_to": "industry"
  }
}
```

**Supported operators:**

* `is`, `is not`
* `is greater than`, `is less than`
* `is greater than or equal to`, `is less than or equal to`
* `is before`, `is after` (for dates)
* `contains`, `does not contain` (for text)

## Rate Limits

All API routes share a per-minute rate limit and a monthly usage quota.

**Per-minute limit** (shared across all API routes):

| Plan       | Requests per Minute |
| ---------- | ------------------- |
| Essentials | 10                  |
| Growth     | 60                  |
| Enterprise | 300                 |

**Monthly quota** (per route, resets on the first of each month):

| Plan       | Exports per Month |
| ---------- | ----------------- |
| Essentials | 10,000            |
| Growth     | 30,000            |
| Enterprise | 100,000           |

When a limit is exceeded, the API returns a `429` response with `X-RateLimit-*` and `X-Usage-*` headers indicating current usage and reset timing.

## Examples

<RequestExample>
  ```bash Basic Export theme={null}
  curl -X POST https://app.usehindsight.com/api/v1/deals/export \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "columns": ["name", "amount", "deal_status", "close_date", "owner_id"]
    }'
  ```

  ```bash Filtered Export - Closed Deals Q1 2026 theme={null}
  curl -X POST https://app.usehindsight.com/api/v1/deals/export \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "columns": [
        "name", "amount", "deal_status", "close_date",
        "drivers", "scorecard", "all_competitors", "summary"
      ],
      "filters": {
        "status": ["closedwon", "closedlost"],
        "close_date": {
          "from": "2026-01-01",
          "to": "2026-03-31"
        },
        "analyzed": true
      }
    }'
  ```

  ```bash Export with Competitor Filter theme={null}
  curl -X POST https://app.usehindsight.com/api/v1/deals/export \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "columns": [
        "name", "amount", "deal_status", "all_competitors",
        "drivers", "scorecard"
      ],
      "filters": {
        "competitors": ["comp_abc", "comp_xyz"],
        "competitors_filter_type": "is any of",
        "status": ["Lost"]
      }
    }'
  ```

  ```bash Check Export Status theme={null}
  curl https://app.usehindsight.com/api/v1/deals/export/exp_abc123 \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript Node.js - Start Export theme={null}
  const response = await fetch('https://app.usehindsight.com/api/v1/deals/export', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      columns: ['name', 'amount', 'deal_status', 'close_date', 'owner_id'],
      filters: {
        status: ['closedwon', 'closedlost'],
        close_date: {
          from: '2026-01-01',
          to: '2026-03-31'
        }
      }
    })
  });

  const { export_id } = await response.json();
  console.log('Export started:', export_id);
  ```

  ```javascript Node.js - Poll for Completion theme={null}
  async function waitForExport(exportId) {
    while (true) {
      const response = await fetch(
        `https://app.usehindsight.com/api/v1/deals/export/${exportId}`,
        {
          headers: { 'Authorization': `Bearer ${API_KEY}` }
        }
      );
      
      const status = await response.json();
      
      if (status.status === 'completed') {
        console.log('Export ready!', status.download_url);
        return status.download_url;
      } else if (status.status === 'failed') {
        throw new Error(`Export failed: ${status.error}`);
      }
      
      // Wait 5 seconds before checking again
      await new Promise(resolve => setTimeout(resolve, 5000));
    }
  }

  const downloadUrl = await waitForExport('exp_abc123');
  ```

  ```python Python - Complete Flow theme={null}
  import requests
  import time

  API_KEY = 'your_api_key_here'
  BASE_URL = 'https://app.usehindsight.com/api/v1'

  # Start export
  response = requests.post(
      f'{BASE_URL}/deals/export',
      headers={
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json'
      },
      json={
          'columns': ['name', 'amount', 'deal_status', 'close_date'],
          'filters': {
              'status': ['closewon', 'closedlost'],
              'analyzed': True
          }
      }
  )

  export_id = response.json()['export_id']
  print(f'Export started: {export_id}')

  # Poll for completion
  while True:
      status_response = requests.get(
          f'{BASE_URL}/deals/export/{export_id}',
          headers={'Authorization': f'Bearer {API_KEY}'}
      )
      
      status = status_response.json()
      
      if status['status'] == 'completed':
          print(f'Export ready! Download from: {status["download_url"]}')
          print(f'Rows exported: {status["rows_exported"]}')
          break
      elif status['status'] == 'failed':
          print(f'Export failed: {status["error"]}')
          break
      
      print('Export still processing...')
      time.sleep(5)
  ```
</RequestExample>

## Best Practices

1. **Column Selection**: Only request columns you need to minimize export size and processing time
2. **Polling Interval**: Wait 5-10 seconds between status checks to avoid rate limiting
3. **Download Promptly**: Download the file within 7 days before the URL expires
4. **Filter Early**: Apply filters to reduce export size rather than filtering after download
5. **Pagination Alternative**: For real-time data access, consider using the paginated `/deals` endpoint instead

## Error Responses

| Status Code | Description                                                  |
| ----------- | ------------------------------------------------------------ |
| 400         | Invalid request (e.g., invalid column ID, malformed filters) |
| 401         | Invalid or missing API key                                   |
| 403         | Insufficient permissions                                     |
| 404         | Export ID not found                                          |
| 429         | Rate limit exceeded                                          |
| 500         | Internal server error                                        |

Example error response:

```json theme={null}
{
  "error": "Invalid column IDs: unknown_column, invalid_field",
  "status": 400
}
```


## OpenAPI

````yaml POST /deals/export
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).


    ## Rate Limits


    API and MCP requests are rate-limited per organization. The per-minute rate
    limit is

    shared across API and MCP traffic and uses a 60-second sliding window.
    Direct tool

    calls also consume a monthly usage bucket; `select-deal` and `get-deal`
    consume one

    read each from the shared reads bucket after authorization and validation
    succeed.


    | Plan | Per Minute | Per Month |

    |------|-----------|----------|

    | Essentials | 10 | 10,000 |

    | Growth | 60 | 30,000 |

    | Enterprise | 300 | 100,000 |


    Successful direct-tool responses include `X-RateLimit-Limit`,
    `X-RateLimit-Remaining`,

    `X-RateLimit-Reset` (Unix milliseconds), `X-Usage-Used`, `X-Usage-Limit`,

    `X-Usage-Remaining`, and `X-Usage-Period-End`. When a limit is exceeded, the
    API

    returns a `429` response with the relevant headers.
  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:
  /deals/export:
    post:
      tags:
        - Deals
      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.
      operationId: exportDeals
      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'
components:
  schemas:
    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
    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
  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
    RateLimitExceeded:
      description: >-
        Too many requests - per-minute rate limit or monthly 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.
        X-Usage-Used:
          schema:
            type: integer
          description: Requests consumed from the applicable monthly bucket.
        X-Usage-Limit:
          schema:
            type: integer
          description: Monthly allowance for the applicable usage bucket.
        X-Usage-Remaining:
          schema:
            type: integer
          description: Requests remaining in the applicable monthly usage bucket.
        X-Usage-Period-End:
          schema:
            type: string
            format: date-time
          description: ISO timestamp when the monthly usage period resets.
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: internal_error
              message: An unexpected error occurred
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key from Hindsight dashboard

````