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

# Company Search (Beta)

> Company Search API endpoint: query company profiles using SQL-like syntax with flexible filtering across 50+ data fields.

## Query Format

Write a `SELECT * FROM companies WHERE ...` query. Do **not** include `LIMIT` or `OFFSET` clauses in the SQL — use the `limit` and `offset` parameters instead.

```json theme={null}
{
  "query": "SELECT * FROM companies WHERE industry ILIKE '%software%' AND legion_employee_count > 100",
  "limit": 5
}
```

## Response Shape

```json theme={null}
{
  "matches": [ { "company": { "..." : "..." } } ],
  "total": 3417
}
```

* **`matches`** — capped at the request's `limit` (max 100).
* **`total`** — the full row count matching your WHERE clause across the database, *not* just the returned page. Useful for account-sizing: query for "fintech companies founded after 2018" with `limit: 1` and `total` tells you how many accounts exist. The companion `Total-Count-Status` response header tells you how `total` was derived: `exact` (the true count — selective queries like the one above), `estimate` (on broad, low-selectivity queries the exact count exceeds its time budget, so `total` becomes the query planner's row estimate — treat it as a magnitude, not a precise number), or `page` (neither available; `total` is just the returned page size). Search responses do not include `match_metadata` (that field is only populated by `/company/enrich`).

  A broad query returns the same response shape with an approximate total, flagged by the header:

  ```
  Total-Count-Status: estimate
  ```

  ```json theme={null}
  { "matches": [ { "company": { "..." : "..." } } ], "total": 62000 }
  ```

## Pagination

To page through results beyond the first 100, set `offset` to the number of rows to skip. Maximum `offset` is 10,000.

```json theme={null}
{
  "query": "SELECT * FROM companies WHERE industry ILIKE '%software%' AND legion_employee_count > 100",
  "limit": 100,
  "offset": 100
}
```

Ordering is deterministic within a build — the same request returns the same rows in the same order, so paged requests don't overlap or skip rows. Builds run on a periodic cadence; ordering may change across builds, so paginate within a single client session, not across days.

## Available Columns

### Text Columns

| Column                | Description                                            |
| --------------------- | ------------------------------------------------------ |
| `name_cleaned`        | Normalized company name (lowercased)                   |
| `name_display`        | Display-ready company name (original casing preserved) |
| `domain`              | Primary website domain                                 |
| `industry`            | Industry classification                                |
| `headline_cleaned`    | LinkedIn headline                                      |
| `description_cleaned` | Company description                                    |

### Numeric Columns

| Column                    | Description                      |
| ------------------------- | -------------------------------- |
| `founded`                 | Year founded                     |
| `linkedin_followers`      | LinkedIn follower count          |
| `linkedin_employee_count` | Employee count from LinkedIn     |
| `legion_employee_count`   | Employee count from Data Legion  |
| `legion_average_tenure`   | Average employee tenure (months) |

### Enum Columns

| Column | Values                                                                                |
| ------ | ------------------------------------------------------------------------------------- |
| `type` | `private`, `public`, `nonprofit`, `government_agency`, `educational`                  |
| `size` | `1-10`, `11-50`, `51-200`, `201-500`, `501-1000`, `1001-5000`, `5001-10000`, `10001+` |

### Workforce Analytics Columns

| Column                                                 | Description                                       |
| ------------------------------------------------------ | ------------------------------------------------- |
| `legion_new_hire_count_1m` / `3m` / `6m` / `12m`       | New hires in last 1/3/6/12 months                 |
| `legion_attrition_count_1m` / `3m` / `6m` / `12m`      | Departures in last 1/3/6/12 months                |
| `legion_employee_growth_rate_1m` / `3m` / `6m` / `12m` | Growth rate as a decimal fraction (`0.05` = 5%)   |
| `legion_turnover_rate_1m` / `3m` / `6m` / `12m`        | Turnover rate as a decimal fraction (`0.1` = 10%) |

### Cross-Table Columns

These columns search across related tables and are automatically rewritten to subqueries:

| Column                     | Description         |
| -------------------------- | ------------------- |
| `ticker_symbol` / `ticker` | Stock ticker symbol |
| `exchange`                 | Stock exchange      |
| `social_url`               | Social media URLs   |
| `alt_domain`               | Alternative domains |

## Example Queries

```sql theme={null}
-- Software companies with 100+ employees
SELECT * FROM companies WHERE industry ILIKE '%software%' AND legion_employee_count > 100

-- Public companies in healthcare
SELECT * FROM companies WHERE type = 'public' AND industry ILIKE '%health%'

-- Fast-growing companies (20%+ growth in last 6 months)
SELECT * FROM companies WHERE legion_employee_growth_rate_6m > 0.2

-- Companies with high turnover (30%+ in last 12 months)
SELECT * FROM companies WHERE legion_turnover_rate_12m > 0.3 AND legion_employee_count > 50
```


## OpenAPI

````yaml POST /company/search
openapi: 3.1.0
info:
  title: Data Legion API
  description: API for enriching, searching, and discovering person and company data
  version: 1.0.0
servers:
  - url: https://api.datalegion.ai
security:
  - APIKeyHeader: []
paths:
  /company/search:
    post:
      tags:
        - company
        - search
      summary: Search companies using SQL query
      description: >-
        Execute a SQL query against the company database. The query must not
        contain LIMIT or OFFSET clauses - use the 'limit' and 'offset'
        parameters for pagination.
      operationId: search_companies_company_search_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompanySearchRequest'
      responses:
        '200':
          description: Success - query executed and results returned
          headers:
            Total-Count-Status:
              $ref: '#/components/headers/TotalCountStatus'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyMatchesResponse'
              example:
                matches:
                  - company:
                      legion_id: c8a1b2c3-d4e5-6f7a-8b9c-0d1e2f3a4b5c
                      name:
                        cleaned: stripe inc
                        display: Stripe
                        raw:
                          - Stripe, Inc.
                      domain: stripe.com
                      industry: financial services
                      type: private
                      size: 5001-10000
                      founded: 2010
                      linkedin_url: https://www.linkedin.com/company/stripe
                      linkedin_id: '2135371'
                      legion_employee_count: 8500
                      legion_average_tenure: 28.4
                      legion_employee_growth_rate:
                        1m: 0.012
                        3m: 0.035
                        6m: 0.068
                        12m: 0.125
                      last_seen: 2026-01
                      num_sources: 5
                total: 3417
        '400':
          description: Bad request - invalid query or contains LIMIT clause
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized - invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Payment required - insufficient credits or expired contract
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden - API key not authorized for this endpoint
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '408':
          description: Request timeout - the query exceeded the execution time limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: Payload too large - request body exceeds size limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation error - invalid field format or value
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Too many requests - rate limit exceeded (50 requests per minute)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Service unavailable - database or service temporarily unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    CompanySearchRequest:
      properties:
        query:
          type: string
          maxLength: 10000
          minLength: 1
          title: Query
          description: SQL query against company data (must not contain LIMIT)
        limit:
          type: integer
          maximum: 100
          minimum: 1
          title: Limit
          description: Maximum results to return
        offset:
          type: integer
          maximum: 10000
          minimum: 0
          title: Offset
          description: >-
            Number of results to skip for pagination (0-10000). Stable within a
            build; ordering may change across builds.
          default: 0
        titlecase:
          type: boolean
          title: Titlecase
          description: >-
            If true, format text fields in title case (names, company names,
            locations). Raw fields, IDs, URLs, codes, and confidence fields are
            excluded.
          default: false
        include_fields:
          anyOf:
            - type: string
            - type: 'null'
          title: Include Fields
          description: >-
            Comma-separated list of fields to include in response. If omitted,
            all fields are returned.
        exclude_fields:
          anyOf:
            - type: string
            - type: 'null'
          title: Exclude Fields
          description: >-
            Comma-separated list of fields to exclude from response. Applied
            after include_fields filter.
        pretty_print:
          type: boolean
          title: Pretty Print
          description: If true, pretty-print JSON response with indentation.
          default: false
      type: object
      required:
        - query
        - limit
      title: CompanySearchRequest
      description: Request model for SQL query-based company search.
      example:
        query: >-
          SELECT * FROM companies WHERE industry ILIKE '%software%' AND
          size='1001-5000'
        limit: 10
    CompanyMatchesResponse:
      properties:
        matches:
          items:
            $ref: '#/components/schemas/CompanyMatchResponse'
          type: array
          title: Matches
          description: >-
            List of matches sorted by confidence (descending). Capped at the
            request's `limit`.
        total:
          type: integer
          title: Total
          description: >-
            For /company/search and /company/discover, the total number of rows
            matching the query's WHERE clause across the database (not just this
            page). For /company/enrich, the number of matches found for the
            input identifier. On search/discover, if the exact count exceeds its
            time budget (broad, low-selectivity queries) it falls back to the
            query planner's row estimate, and if that is unavailable, to the
            size of the returned page; the response header `Total-Count-Status`
            reports which (`exact`, `estimate`, or `page`).
      type: object
      required:
        - matches
        - total
      title: CompanyMatchesResponse
    ErrorResponse:
      properties:
        error:
          type: string
          title: Error
          description: Error type/code
        message:
          type: string
          title: Message
          description: Human-readable error message
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - items: {}
              type: array
            - type: 'null'
          title: Details
          description: Additional error details (for validation errors)
      type: object
      required:
        - error
        - message
      title: ErrorResponse
      description: Error response model for customer-facing API.
    CompanyMatchResponse:
      properties:
        company:
          $ref: '#/components/schemas/CompanyResponse'
        match_metadata:
          anyOf:
            - $ref: '#/components/schemas/MatchMetadata'
            - type: 'null'
      type: object
      required:
        - company
      title: CompanyMatchResponse
    CompanyResponse:
      properties:
        legion_id:
          type: string
          title: Legion Id
        name:
          anyOf:
            - $ref: '#/components/schemas/CompanyNameResponse'
            - type: 'null'
        headline:
          anyOf:
            - $ref: '#/components/schemas/CleanedRawResponse'
            - type: 'null'
        description:
          anyOf:
            - $ref: '#/components/schemas/CleanedRawResponse'
            - type: 'null'
        domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Domain
        linkedin_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Linkedin Url
        linkedin_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Linkedin Id
        linkedin_followers:
          anyOf:
            - type: integer
            - type: 'null'
          title: Linkedin Followers
        linkedin_employee_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Linkedin Employee Count
        industry:
          anyOf:
            - type: string
            - type: 'null'
          title: Industry
        type:
          anyOf:
            - type: string
            - type: 'null'
          title: Type
        size:
          anyOf:
            - type: string
            - type: 'null'
          title: Size
        founded:
          anyOf:
            - type: integer
            - type: 'null'
          title: Founded
        legion_employee_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Legion Employee Count
        legion_average_tenure:
          anyOf:
            - type: number
            - type: 'null'
          title: Legion Average Tenure
        legion_new_hire_count:
          anyOf:
            - $ref: '#/components/schemas/TimeBucketIntResponse'
            - type: 'null'
        legion_attrition_count:
          anyOf:
            - $ref: '#/components/schemas/TimeBucketIntResponse'
            - type: 'null'
        legion_turnover_rate:
          anyOf:
            - $ref: '#/components/schemas/TimeBucketFloatResponse'
            - type: 'null'
        legion_employee_growth_rate:
          anyOf:
            - $ref: '#/components/schemas/TimeBucketFloatResponse'
            - type: 'null'
        legion_seniority_distribution:
          anyOf:
            - type: object
              additionalProperties:
                type: integer
            - type: 'null'
          title: Seniority Distribution
          description: >-
            Employee count by seniority level (c_level, owner, partner, vp,
            director, manager, senior, junior, training, intern)
        legion_job_function_distribution:
          anyOf:
            - type: object
              additionalProperties:
                type: integer
            - type: 'null'
          title: Job Function Distribution
          description: Employee count by job function (engineering, sales, marketing, etc.)
        legion_expense_category_distribution:
          anyOf:
            - type: object
              additionalProperties:
                type: integer
            - type: 'null'
          title: Expense Category Distribution
          description: >-
            Employee count by P&L expense category (general_and_administrative,
            research_and_development, sales_and_marketing, cost_of_services,
            not_applicable)
        legion_tenure_distribution:
          anyOf:
            - type: object
              additionalProperties:
                type: integer
            - type: 'null'
          title: Tenure Distribution
          description: Employee count by tenure bucket (<1yr, 1-2yr, 2-5yr, 5-10yr, 10+yr)
        legion_education_distribution:
          anyOf:
            - type: object
              additionalProperties:
                type: integer
            - type: 'null'
          title: Education Distribution
          description: >-
            Employee count by education level (doctorate, masters, bachelors,
            associates, high_school)
        legion_seniority_growth_rate:
          anyOf:
            - type: object
              additionalProperties:
                $ref: '#/components/schemas/TimeBucketFloatResponse'
            - type: 'null'
          title: Seniority Growth Rate
          description: Growth rate per seniority level with time buckets (1m, 3m, 6m, 12m)
        legion_job_function_growth_rate:
          anyOf:
            - type: object
              additionalProperties:
                $ref: '#/components/schemas/TimeBucketFloatResponse'
            - type: 'null'
          title: Job Function Growth Rate
          description: Growth rate per job function with time buckets (1m, 3m, 6m, 12m)
        legion_expense_category_growth_rate:
          anyOf:
            - type: object
              additionalProperties:
                $ref: '#/components/schemas/TimeBucketFloatResponse'
            - type: 'null'
          title: Expense Category Growth Rate
          description: Growth rate per expense category with time buckets (1m, 3m, 6m, 12m)
        tickers:
          items:
            $ref: '#/components/schemas/CompanyTickerResponse'
          type: array
          title: Tickers
          default: []
        socials:
          items:
            $ref: '#/components/schemas/CompanySocialResponse'
          type: array
          title: Socials
          default: []
        domains:
          items:
            $ref: '#/components/schemas/CompanyDomainResponse'
          type: array
          title: Domains
          default: []
        legion_employee_count_by_month:
          items:
            $ref: '#/components/schemas/EmployeeCountByMonthResponse'
          type: array
          title: Legion Employee Count By Month
          default: []
        num_sources:
          anyOf:
            - type: integer
            - type: 'null'
          title: Num Sources
        last_seen:
          anyOf:
            - type: string
              description: YYYY-MM format
            - type: 'null'
          title: Last Seen
        build_version:
          anyOf:
            - type: string
            - type: 'null'
          title: Build Version
      type: object
      required:
        - legion_id
      title: CompanyResponse
      description: Complete company enrichment response.
    MatchMetadata:
      properties:
        matched_on:
          items:
            type: string
          type: array
          title: Matched On
          description: Fields that matched between request and person
        match_type:
          type: string
          title: Match Type
          description: 'Type of match: exact, fuzzy, or partial'
        match_confidence:
          type: string
          title: Match Confidence
          description: 'Match confidence level: high, moderate, or low'
      type: object
      required:
        - match_type
        - match_confidence
      title: MatchMetadata
      description: Metadata about the match.
    CompanyNameResponse:
      properties:
        cleaned:
          anyOf:
            - type: string
            - type: 'null'
          title: Cleaned
        display:
          anyOf:
            - type: string
            - type: 'null'
          title: Display
          description: Best-quality name with original casing preserved (premium tier)
        raw:
          items:
            type: string
          type: array
          title: Raw
          default: []
      type: object
      title: CompanyNameResponse
      description: Company name structure with cleaned, display, and raw[] variants.
    CleanedRawResponse:
      properties:
        cleaned:
          anyOf:
            - type: string
            - type: 'null'
          title: Cleaned
        raw:
          items:
            type: string
          type: array
          title: Raw
          default: []
      type: object
      title: CleanedRawResponse
      description: >-
        Generic {cleaned, raw[]} structure used for titles, degrees, headlines,
        summaries, skills, languages, and certification names/institutions.
    TimeBucketIntResponse:
      properties:
        1m:
          anyOf:
            - type: integer
            - type: 'null'
          title: 1m
          description: Value over the last month
        3m:
          anyOf:
            - type: integer
            - type: 'null'
          title: 3m
          description: Value over the last 3 months
        6m:
          anyOf:
            - type: integer
            - type: 'null'
          title: 6m
          description: Value over the last 6 months
        12m:
          anyOf:
            - type: integer
            - type: 'null'
          title: 12m
          description: Value over the last 12 months
      type: object
      title: TimeBucketIntResponse
      description: Time-bucketed integer values (1m, 3m, 6m, 12m).
    TimeBucketFloatResponse:
      properties:
        1m:
          anyOf:
            - type: number
            - type: 'null'
          title: 1m
          description: Rate over the last month
        3m:
          anyOf:
            - type: number
            - type: 'null'
          title: 3m
          description: Rate over the last 3 months
        6m:
          anyOf:
            - type: number
            - type: 'null'
          title: 6m
          description: Rate over the last 6 months
        12m:
          anyOf:
            - type: number
            - type: 'null'
          title: 12m
          description: Rate over the last 12 months
      type: object
      title: TimeBucketFloatResponse
      description: Time-bucketed float values (1m, 3m, 6m, 12m).
    CompanyTickerResponse:
      properties:
        symbol:
          anyOf:
            - type: string
            - type: 'null'
          title: Symbol
        exchange:
          anyOf:
            - type: string
            - type: 'null'
          title: Exchange
      type: object
      title: CompanyTickerResponse
    CompanySocialResponse:
      properties:
        network:
          anyOf:
            - type: string
            - type: 'null'
          title: Network
          description: Social network name (e.g., x, github, facebook)
        url:
          anyOf:
            - type: string
            - type: 'null'
          title: Url
          description: Profile URL
        username:
          anyOf:
            - type: string
            - type: 'null'
          title: Username
          description: Username or handle
        id:
          anyOf:
            - type: string
            - type: 'null'
          title: Id
          description: Account ID
      type: object
      title: CompanySocialResponse
      description: Company social media profile.
    CompanyDomainResponse:
      properties:
        domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Domain
          description: Associated company domain
      type: object
      title: CompanyDomainResponse
      description: Company alternative domain.
    EmployeeCountByMonthResponse:
      properties:
        month:
          anyOf:
            - type: string
            - type: 'null'
          title: Month
          description: YYYY-MM format
        count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Count
        net_change:
          anyOf:
            - type: integer
            - type: 'null'
          title: Net Change
        growth_rate:
          anyOf:
            - type: number
            - type: 'null'
          title: Growth Rate
        hires:
          anyOf:
            - type: integer
            - type: 'null'
          title: Hires
        departures:
          anyOf:
            - type: integer
            - type: 'null'
          title: Departures
      type: object
      title: EmployeeCountByMonthResponse
  headers:
    TotalCountStatus:
      description: >-
        `exact` when the response `total` is the full row count matching the
        WHERE clause across the database. `estimate` when the exact count
        exceeded its time budget (broad, low-selectivity queries) and `total` is
        the query planner's row estimate (a rough magnitude, not a precise
        figure). `page` when neither was available and `total` is just the size
        of the returned page.
      schema:
        type: string
        enum:
          - exact
          - estimate
          - page
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: API-Key

````