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

# Search Companies by Tech Stack with Intent

> **Asynchronous, LLM-verified variant of [Search Companies By Tech Stack](/agent-primitives/search-companies-by-tech-stack).** Same tech-in-job-postings search, plus an `activity` you supply - each company's most recent matching posting is verified against that activity, and only companies whose posting demonstrates the tech being used **in the way you described** are returned.

<Info>**No API key yet?** [Sign up via Agent Auth](/agent-auth/agent-auth/agent-sign-up) to get your `X-API-Key` - the only required header for this endpoint.</Info>

Use it when the tech mention alone is too noisy and you care *how* the tech shows up:
- `tech=Snowflake` + `activity=migrating off Redshift to Snowflake`
- `tech=Kubernetes` + `activity=migrating workloads from VMs to Kubernetes`
- `tech=dbt` + `activity=building a central analytics engineering team that owns dbt models`

The `activity` acts as a **hard filter**: if the posting mentions the tech but in a different context (a customer reference, a different product with the same name, an unrelated use-case), the company is dropped. Each returned company carries an `intent.reason` quoting the exact posting phrases that support the verdict, plus the qualified posting itself (`intent.qualified_job`).

## How it runs

The call returns a `job_id` immediately and the scan runs as a background job: companies are verified in ranked order (most matching posts first) and the scan **early-stops once `limit` companies qualify** - you only pay for what you asked for. A broad activity completes in under a minute; a rare one scans deeper and can take a few minutes.

**Poll `GET /api/v2/tech/companies/intent-search/{job_id}`** ("Tech Intent Search Results", listed under Agent Helpers) until `status` is `completed`, then walk the result pages using `next_cursor`.

## Filters & enrichment

All the firmographic filters from Search Companies By Tech Stack work here (`hq_country_code`, `min_employee_count`, `max_employee_count`) and auto-enable enrichment. Set `enrich=true` without filters to hydrate qualified companies with firmographics (employee count, HQ, website, LinkedIn, industries, funding, revenue).

## Credits
Charged when the job completes - empty result sets are free. The exact amount is echoed in the manifest's `credits_consumed`. Polling is free.

The response returns a `job_id`; then poll `GET /api/v2/tech/companies/intent-search/{job_id}` for status and results.



## OpenAPI

````yaml agent-primitives/openapi.json POST /api/v2/tech/companies/intent-search
openapi: 3.1.0
info:
  title: OpenFunnel Agent Primitives
  version: 1.0.0
servers:
  - url: https://api.openfunnel.dev
security: []
paths:
  /api/v2/tech/companies/intent-search:
    post:
      tags:
        - Company Search
      summary: Search Companies by Tech Stack with Intent
      description: >-
        **Asynchronous, LLM-verified variant of [Search Companies By Tech
        Stack](/agent-primitives/search-companies-by-tech-stack).** Same
        tech-in-job-postings search, plus an `activity` you supply - each
        company's most recent matching posting is verified against that
        activity, and only companies whose posting demonstrates the tech being
        used **in the way you described** are returned.


        <Info>**No API key yet?** [Sign up via Agent
        Auth](/agent-auth/agent-auth/agent-sign-up) to get your `X-API-Key` -
        the only required header for this endpoint.</Info>


        Use it when the tech mention alone is too noisy and you care *how* the
        tech shows up:

        - `tech=Snowflake` + `activity=migrating off Redshift to Snowflake`

        - `tech=Kubernetes` + `activity=migrating workloads from VMs to
        Kubernetes`

        - `tech=dbt` + `activity=building a central analytics engineering team
        that owns dbt models`


        The `activity` acts as a **hard filter**: if the posting mentions the
        tech but in a different context (a customer reference, a different
        product with the same name, an unrelated use-case), the company is
        dropped. Each returned company carries an `intent.reason` quoting the
        exact posting phrases that support the verdict, plus the qualified
        posting itself (`intent.qualified_job`).


        ## How it runs


        The call returns a `job_id` immediately and the scan runs as a
        background job: companies are verified in ranked order (most matching
        posts first) and the scan **early-stops once `limit` companies qualify**
        - you only pay for what you asked for. A broad activity completes in
        under a minute; a rare one scans deeper and can take a few minutes.


        **Poll `GET /api/v2/tech/companies/intent-search/{job_id}`** ("Tech
        Intent Search Results", listed under Agent Helpers) until `status` is
        `completed`, then walk the result pages using `next_cursor`.


        ## Filters & enrichment


        All the firmographic filters from Search Companies By Tech Stack work
        here (`hq_country_code`, `min_employee_count`, `max_employee_count`) and
        auto-enable enrichment. Set `enrich=true` without filters to hydrate
        qualified companies with firmographics (employee count, HQ, website,
        LinkedIn, industries, funding, revenue).


        ## Credits

        Charged when the job completes - empty result sets are free. The exact
        amount is echoed in the manifest's `credits_consumed`. Polling is free.


        The response returns a `job_id`; then poll `GET
        /api/v2/tech/companies/intent-search/{job_id}` for status and results.
      operationId: tech_intent_search_submit_api_v2_tech_companies_intent_search_post
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
            title: X-Api-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TechIntentSearchRequest'
      responses:
        '200':
          description: Job accepted. Returns a `job_id` to poll for status and results.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TechIntentSubmitResponse'
        '400':
          description: >-
            Unknown `hq_country_code`, `min_employee_count` greater than
            `max_employee_count`, or insufficient credits for the requested
            `limit`.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit reached for this API key or user.
        '503':
          description: >-
            Tech intent search is temporarily unavailable. Please try again
            shortly.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailableResponse'
      x-codeSamples:
        - lang: bash
          label: Submit a job
          source: >-
            curl -sS -X POST
            "https://api.openfunnel.dev/api/v2/tech/companies/intent-search" \
              -H "X-API-Key: YOUR_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"tech": "Snowflake", "activity": "migrating off Redshift to Snowflake", "lookback_days": 180, "limit": 50}'
        - lang: bash
          label: With firmographic filters
          source: >-
            curl -sS -X POST
            "https://api.openfunnel.dev/api/v2/tech/companies/intent-search" \
              -H "X-API-Key: YOUR_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"tech": "Kubernetes", "activity": "migrating workloads from VMs to Kubernetes", "variations": ["K8s"], "limit": 25, "hq_country_code": "USA", "min_employee_count": 200, "max_employee_count": 5000}'
components:
  schemas:
    TechIntentSearchRequest:
      type: object
      title: TechIntentSearchRequest
      description: >-
        Request body for the async tech + activity-intent search. Same search
        inputs as Search Companies By Tech Stack, plus the required `activity`
        to verify and a `limit` on qualified companies.
      required:
        - tech
        - activity
      properties:
        tech:
          type: string
          minLength: 1
          maxLength: 128
          title: Tech
          description: >-
            Technology to search for in job descriptions (e.g. 'Snowflake',
            'Kubernetes').
        activity:
          type: string
          minLength: 1
          maxLength: 500
          title: Activity
          description: >-
            The activity intent to verify, e.g. 'migrating off Redshift to
            Snowflake' or 'building a central analytics engineering team that
            owns dbt models'. Acts as a HARD filter: a company qualifies only
            when its job posting mentions the tech in a way consistent with this
            activity.
          examples:
            - migrating off Redshift to Snowflake
            - migrating workloads from VMs to Kubernetes
        variations:
          anyOf:
            - type: array
              items:
                type: string
            - type: 'null'
          title: Variations
          description: >-
            Optional alternate phrasings of the tech (e.g. 'K8s' for
            Kubernetes). Each is OR-matched as a phrase.
        lookback_days:
          type: integer
          minimum: 1
          maximum: 365
          default: 365
          title: Lookback Days
          description: Lookback window in days (1–365).
        limit:
          type: integer
          minimum: 1
          maximum: 500
          default: 100
          title: Limit
          description: >-
            Maximum number of QUALIFIED companies to return. The scan walks the
            ranked pool and early-stops once this many companies pass intent
            verification.
        exclude_vendor:
          type: boolean
          default: true
          title: Exclude Vendor
          description: >-
            When true (default), excludes job posts from the vendor of the
            technology being searched.
        exclude_aggregators:
          type: boolean
          default: true
          title: Exclude Aggregators
          description: >-
            Exclude well-known LinkedIn job aggregators and reposters
            (`jobs-via-*`, `lensa`, `ziprecruiter`, etc.). ON by default.
        exclude_company_slugs:
          anyOf:
            - type: array
              items:
                type: string
            - type: 'null'
          title: Exclude Company Slugs
          description: >-
            Additional LinkedIn company slugs to exclude on top of the default
            aggregator block-list.
        enrich:
          type: boolean
          default: false
          title: Enrich
          description: >-
            Hydrate qualified companies with firmographics (employee count,
            website, LinkedIn, HQ, industries, funding, revenue). Auto-enabled
            when any firmographic filter is set.
        hq_country_code:
          anyOf:
            - type: string
              minLength: 3
              maxLength: 3
            - type: 'null'
          title: Hq Country Code
          description: >-
            Filter by company HQ ISO 3166-1 alpha-3 code (e.g. `USA`, `GBR`,
            `IND`, `DEU`). Full list of 250 codes via `GET
            /api/v2/tech/country-options` (under Agent Helpers). Auto-enables
            `enrich`.
        min_employee_count:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Min Employee Count
          description: >-
            Inclusive lower bound on company employee count. Auto-enables
            `enrich`.
        max_employee_count:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Max Employee Count
          description: >-
            Inclusive upper bound on company employee count. Auto-enables
            `enrich`.
    TechIntentSubmitResponse:
      type: object
      title: TechIntentSubmitResponse
      description: Returned immediately when a tech intent-search job is submitted.
      required:
        - job_id
        - message
        - requested_limit
      properties:
        job_id:
          type: string
          title: Job Id
          description: >-
            Async job id. Poll `GET
            /api/v2/tech/companies/intent-search/{job_id}` for status and
            results.
        status:
          type: string
          default: pending
          title: Status
          description: Job status at submit time (always `pending`).
        message:
          type: string
          title: Message
          description: Human-readable next-step hint.
        requested_limit:
          type: integer
          title: Requested Limit
          description: The requested maximum number of qualified companies.
    HTTPValidationError:
      type: object
      properties:
        detail:
          type: array
          items:
            $ref: '#/components/schemas/ValidationError'
    ServiceUnavailableResponse:
      type: object
      properties:
        detail:
          type: string
          description: Human-readable explanation of why the service is unavailable.
      title: ServiceUnavailableResponse
    ValidationError:
      type: object
      required:
        - loc
        - msg
        - type
      properties:
        loc:
          type: array
          items:
            anyOf:
              - type: string
              - type: integer
        msg:
          type: string
        type:
          type: string

````