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

# Adoption and churn signals API

> Find domains that just adopted or dropped a technology, scoped by technology or category, with confidence scoring and firmographic filters. Costs 1 credit per request.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="What is the difference between count and total_sites?">
    `count` is how many rows came back in this response, capped by your `limit`. `total_sites` is the corpus-wide number of distinct sites with this event in the window, ignoring `limit` entirely. Use `total_sites` for headline figures like "2,847 sites installed this technology this month" and `count` only to page through rows. `total_sites` can be `null` on very large categories if the count query runs too long — the row list still returns.
  </Accordion>

  <Accordion title="How should I read the confidence score?">
    Each row carries `confidence` with a score from 0 to 100 and a label. It combines three things: how reliable the detection method is, how many distinct scans saw the technology (`detection_count`), and how consistently it was seen (`detection_rate`). A detection seen on only one scan caps at `medium` no matter how reliable the method, because a single snapshot is not corroboration. A churn with fewer than 2 detections caps at `low` — if we only ever caught the technology once, its removal is unconfirmed.
  </Accordion>

  <Accordion title="Why do I get fewer results when I add a country filter?">
    Firmographic filters switch the query into filter mode, which restricts results to domains with a matched LinkedIn company record that passes your predicates. Roughly 23–30% of technology domains have a company match, so filtering shrinks both the rows and `total_sites`. The response's `firmographics.note` says so explicitly. If you want company data attached without losing rows, pass `company=true` on its own instead.
  </Accordion>

  <Accordion title="What does the first-seen gate do on adoption?">
    A domain we crawl for the first time appears to have "adopted" everything on it at once, which is not adoption — it is discovery. By default those first-crawl domains are excluded, and the response confirms it with `excludes_first_seen: true`. Set `include_first_seen=true` to turn the gate off, which gives you a newly-discovered-domains feed rather than genuine adoption.
  </Accordion>

  <Accordion title="Can I scope a signal to a whole category?">
    Yes. Pass `category_id` instead of a technology and the query fans out to every detectable technology whose *primary* category is that one, with each result row naming the specific technology involved. Note that primary category is the only axis used, so a tool cross-listed elsewhere will not appear under a secondary category.
  </Accordion>

  <Accordion title="Why is there a separate rate limit on signals?">
    Signal queries are heavy scans over the detection corpus. Everything under `/v1/signals/*` carries an additional per-key limit of 10, 30 or 60 requests per minute depending on plan, on top of your general plan limit. A signals 429 identifies itself with `"scope": "signals"` in the error details.
  </Accordion>
</AccordionGroup>


## OpenAPI

````yaml GET /v1/signals/{type}
openapi: 3.1.0
info:
  title: TechnologyChecker API
  description: >-
    Discover technology stacks, track market trends, and enrich data with
    company intelligence.
  version: 1.0.0
  contact:
    name: TechnologyChecker Support
    email: support@technologychecker.io
    url: https://technologychecker.io
servers:
  - url: https://api.technologychecker.io
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Domain technologies
    description: Look up technologies detected on any domain
  - name: Technology data
    description: Search, look up, and get details on tracked technologies
  - name: Market intelligence
    description: Technology stats, trends, and market share
  - name: Company data
    description: Firmographic and company intelligence
  - name: Live detection
    description: Real-time technology detection with browser rendering
  - name: Signals
    description: >-
      Intent signals derived from technology state transitions: who adopted, who
      churned, who switched, and who has a gap in their stack.
  - name: Alerts
    description: >-
      Saved signal queries delivered to your webhook. Every signal you can
      query, you can subscribe to.
  - name: Audiences
    description: >-
      Saved groups of domains — uploaded lists or computed recipes — that you
      can profile, slice and monitor.
  - name: Lead lists
    description: >-
      Build and export targeted domain lists combining technology detection with
      company data.
paths:
  /v1/signals/{type}:
    get:
      tags:
        - Signals
      summary: Adoption and churn signals API
      description: >-
        Domains where an adoption or churn happened inside a look-back window,
        scoped by a technology or a whole category. Returns the matching rows
        plus `total_sites`, the corpus-wide count of distinct sites with the
        event (not capped by `limit`).


        Costs 1 credit. Endpoints under `/v1/signals` carry a tighter per-key
        rate limit than the rest of the API.
      operationId: getSignalsByType
      parameters:
        - name: type
          in: path
          required: true
          description: >-
            The signal type. `churn` = a technology the domain had is now gone.
            `adoption` = a technology the domain newly started using.
          schema:
            type: string
            enum:
              - churn
              - adoption
            example: adoption
        - name: technology_id
          in: query
          required: false
          description: >-
            Scope by BuiltWith technology id. Provide exactly one of
            `technology_id`, `technology` or `category_id`.
          schema:
            type: integer
          example: 2184
        - name: technology
          in: query
          required: false
          description: Scope by exact technology name. The technology must be detectable.
          schema:
            type: string
          example: Shopify
        - name: category_id
          in: query
          required: false
          description: >-
            Scope by category — fans out to every detectable technology whose
            *primary* category is this one. Each result row names the specific
            technology.
          schema:
            type: integer
          example: 202
        - name: window
          in: query
          required: false
          description: Look-back window in days. Accepts `30` or `30d`. Clamped to 1–365.
          schema:
            type: string
            default: '30'
          example: '30'
        - name: limit
          in: query
          required: false
          description: Rows returned. Clamped to 1–1000.
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 1000
        - name: min_confidence
          in: query
          required: false
          description: Minimum `detection_rate` for a row to be returned.
          schema:
            type: number
            format: float
            default: 0.5
            minimum: 0
            maximum: 1
        - name: include_first_seen
          in: query
          required: false
          description: >-
            Adoption only. `true` disables the first-seen gate and counts
            first-time-crawled domains as adopters — a newly-discovered-domains
            feed, not genuine adoption.
          schema:
            type: boolean
            default: false
        - $ref: '#/components/parameters/FirmoCountry'
        - $ref: '#/components/parameters/FirmoCity'
        - $ref: '#/components/parameters/FirmoState'
        - $ref: '#/components/parameters/FirmoIndustry'
        - $ref: '#/components/parameters/FirmoIndustryCode'
        - $ref: '#/components/parameters/FirmoEmployees'
        - $ref: '#/components/parameters/FirmoCompanyType'
        - $ref: '#/components/parameters/FirmoFoundedMin'
        - $ref: '#/components/parameters/FirmoFoundedMax'
        - $ref: '#/components/parameters/FirmoCompany'
        - $ref: '#/components/parameters/WebHasEmail'
        - $ref: '#/components/parameters/WebHasPhone'
        - $ref: '#/components/parameters/WebSocial'
        - $ref: '#/components/parameters/WebLanguage'
        - $ref: '#/components/parameters/WebCountry'
        - $ref: '#/components/parameters/SegmentId'
      responses:
        '200':
          description: Matching domains and the corpus-wide site count
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      signal:
                        type: object
                        properties:
                          type:
                            type: string
                            example: adoption
                          verb:
                            type: string
                            example: adopted
                      scope:
                        type: string
                        enum:
                          - technology
                          - category
                        example: category
                      technology:
                        type: object
                        nullable: true
                        description: Set for technology scope, `null` for category scope.
                      category:
                        type: object
                        nullable: true
                        description: Set for category scope, `null` for technology scope.
                        properties:
                          id:
                            type: integer
                            example: 202
                          name:
                            type: string
                            example: Email Marketing
                          technology_count:
                            type: integer
                            example: 37
                      window_days:
                        type: integer
                        example: 30
                      min_confidence:
                        type: number
                        format: float
                        example: 0.5
                      excludes_first_seen:
                        type: boolean
                        description: Adoption only — first-crawl domains were excluded.
                        example: true
                      total_sites:
                        type: integer
                        nullable: true
                        description: >-
                          Distinct sites with this event across the whole
                          corpus, not capped by `limit`. `null` when the count
                          query was too slow (very large categories).
                        example: 2479434
                      domains:
                        type: array
                        items:
                          $ref: '#/components/schemas/SignalEvent'
                      firmographics:
                        $ref: '#/components/schemas/FirmographicsEcho'
                      count:
                        type: integer
                        description: >-
                          Rows returned, capped at `limit`. Use `total_sites`
                          for the corpus total.
                        example: 1
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    FirmoCountry:
      name: country
      in: query
      required: false
      description: Filter to companies in this country (case-insensitive).
      schema:
        type: string
      example: united states
    FirmoCity:
      name: city
      in: query
      required: false
      description: Filter to companies in this city (case-insensitive).
      schema:
        type: string
    FirmoState:
      name: state
      in: query
      required: false
      description: Filter to companies in this state or region (case-insensitive).
      schema:
        type: string
    FirmoIndustry:
      name: industry
      in: query
      required: false
      description: Filter to companies in this industry (case-insensitive).
      schema:
        type: string
      example: retail
    FirmoIndustryCode:
      name: industry_code
      in: query
      required: false
      description: Filter by exact LinkedIn industry code.
      schema:
        type: integer
    FirmoEmployees:
      name: employees
      in: query
      required: false
      description: >-
        Filter by exact LinkedIn employee band. Unknown bands are rejected with
        `INVALID_EMPLOYEE_BAND` and the allowed list.
      schema:
        type: string
      example: 51-200
    FirmoCompanyType:
      name: company_type
      in: query
      required: false
      description: Filter by exact company type.
      schema:
        type: string
      example: Privately Held
    FirmoFoundedMin:
      name: founded_min
      in: query
      required: false
      description: Only companies founded in or after this year.
      schema:
        type: integer
        minimum: 1800
        maximum: 2025
    FirmoFoundedMax:
      name: founded_max
      in: query
      required: false
      description: Only companies founded in or before this year.
      schema:
        type: integer
        minimum: 1800
        maximum: 2025
    FirmoCompany:
      name: company
      in: query
      required: false
      description: >-
        Set to `true` to attach the company card without filtering results
        (enrich-only mode).
      schema:
        type: boolean
      example: true
    WebHasEmail:
      name: has_email
      in: query
      required: false
      description: >-
        Filter to domains where the crawler found (or did not find) an email
        address. `false` is a real filter, not a no-op.
      schema:
        type: boolean
    WebHasPhone:
      name: has_phone
      in: query
      required: false
      description: >-
        Filter to domains where the crawler found (or did not find) a phone
        number.
      schema:
        type: boolean
    WebSocial:
      name: social
      in: query
      required: false
      description: Filter to domains publishing a profile on this platform.
      schema:
        type: string
        enum:
          - linkedin
          - x
          - facebook
          - instagram
          - youtube
          - github
          - tiktok
          - discord
          - reddit
          - crunchbase
          - slack
      example: instagram
    WebLanguage:
      name: language
      in: query
      required: false
      description: Filter by the site's primary language.
      schema:
        type: string
      example: de
    WebCountry:
      name: web_country
      in: query
      required: false
      description: >-
        Filter by the country the site declares in its schema.org markup.
        Accepts ISO-2, English name or common variants.
      schema:
        type: string
      example: USA
    SegmentId:
      name: segment_id
      in: query
      required: false
      description: >-
        Apply a saved audience instead of inline filters. Filter audiences
        replay their firmographic predicates; list audiences restrict rows to
        their member domains. Mutually exclusive with inline firmographic
        parameters.
      schema:
        type: string
      example: seg_8f3a2c1b
  schemas:
    SignalEvent:
      type: object
      description: >-
        One adoption or churn event: a domain and the technology transition
        observed on it.
      properties:
        domain:
          type: string
          example: example.com
        subdomain:
          type: string
          example: WWW.EXAMPLE.COM
        detection_url:
          type: string
          description: >-
            The URL the crawler loaded for this row. An event on
            `docs.example.com` is not an event on the apex — show this host, not
            just `domain`.
          example: https://www.example.com
        technology_id:
          type: integer
          example: 900783
        technology_name:
          type: string
          example: Google Workspace
        event_at:
          type: string
          description: When the transition was observed (scan time).
          example: '2026-05-31 14:10:33'
        last_detected:
          type: string
          nullable: true
          example: '2026-04-18 07:39:59'
        detection_rate:
          type: number
          format: float
          description: '`detection_count / scan_count` for this host.'
          example: 0.86
        detection_count:
          type: integer
          description: How many distinct scans actually saw this technology.
          example: 6
        churn_reliability:
          type: string
          nullable: true
          enum:
            - high
            - medium
            - low
            - null
          description: Reliability class of the detection method. Present on churn rows.
        confidence:
          $ref: '#/components/schemas/SignalConfidence'
        company:
          $ref: '#/components/schemas/CompanyCard'
    FirmographicsEcho:
      type: object
      description: Echo of the firmographic predicates that took effect on this request.
      properties:
        applied:
          type: object
          additionalProperties: true
          example:
            country: united states
            employees: 51-200
        filtered:
          type: boolean
          description: >-
            `true` when results were narrowed to matched companies; `false` for
            enrich-only (`company=true`).
          example: true
        note:
          type: string
          example: >-
            Results are limited to domains with a matched LinkedIn company that
            passes these filters (~23–30% of tech-domains have a company match).
    SignalConfidence:
      type: object
      description: >-
        Per-event trust score combining detection method reliability,
        persistence (how many distinct scans saw the technology) and consistency
        (detection rate). A single-scan detection caps at `medium`; a churn with
        `detection_count` below 2 caps at `low`.
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
          example: 79
        label:
          type: string
          enum:
            - high
            - medium
            - low
          example: high
        guard:
          type: string
          nullable: true
          description: >-
            Present when a churn guard capped this score in place, e.g.
            `scan_flap`.
          example: scan_flap
    CompanyCard:
      type: object
      nullable: true
      description: >-
        LinkedIn company card attached when firmographic enrichment is on.
        `null` when the domain has no LinkedIn match (roughly 23–30% of
        technology domains match).
      properties:
        name:
          type: string
          example: Ghostcircusapparel
        industry:
          type: string
          example: Retail Apparel and Fashion
        industry_code:
          type: integer
          example: 18
        employees:
          type: string
          example: 51-200
        country:
          type: string
          example: united states
        city:
          type: string
          nullable: true
        state:
          type: string
          nullable: true
        founded:
          type: integer
          nullable: true
          example: 2015
        company_type:
          type: string
          example: Privately Held
    ApiError:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              example: UNAUTHORIZED
            message:
              type: string
              example: Missing or invalid API key
  responses:
    BadRequest:
      description: Invalid or missing parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            success: false
            error:
              code: VALIDATION_ERROR
              message: >-
                Provide exactly one scope: technology_id, technology or
                category_id.
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    PaymentRequired:
      description: Not enough credits, or the plan does not include this feature
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            success: false
            error:
              code: INSUFFICIENT_CREDITS
              message: Insufficient credits for this request.
              details:
                required: 1
                available: 0
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        API key in format `tapi_live_[32-char]` (live) or `tapi_test_[32-char]`
        (test)

````