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

# List discovery watches

> Returns your discovery watches for this dataset, newest first, as a bare JSON array. Each entry
carries its all-time usage counters (`notifications_count`, `credits_consumed`,
`last_notified_at`) alongside its definition.




## OpenAPI

````yaml /openapi-specs/2025-11-01/watch.yaml get /watch/{dataset}/search
openapi: 3.0.3
info:
  title: Watch API
  version: '2025-11-01'
  description: >
    The Watch API turns a Crustdata query into a recurring feed. A watch runs on
    your schedule and

    delivers only what is new or what changed since its previous run, to a
    webhook, Slack, Google Chat,

    or email.


    There are two kinds of watch, and the kind decides the URL:


    - **Discovery watches** (`/watch/{dataset}/search`) re-run a *search filter*
    and deliver records that
      newly match it. Use one to find people, companies, or jobs you do not know yet. Available for
      `person`, `company`, and `job`.
    - **Entity watches** (`/watch/{dataset}`) monitor a *list you supply* and
    deliver a notification when
      a tracked field on one of those records changes. Use one to follow a known set. Available for
      `person` and `company`.

    Both kinds share the same `config`, `notifications`, and run-history
    surfaces, and both start with a

    free baseline run: a discovery watch delivers a sample of up to 5 current
    matches, an entity watch

    records each subject's starting values and never fires. Every request needs
    an `Authorization` Bearer

    API key and the `x-api-version: 2025-11-01` header.


    **Credits.** A discovery watch is charged per new record delivered: 0.5 for
    a person, 2 for a company,

    0.5 for a job. An entity watch is charged per notification, tiered by
    `config.refresh_frequency_days`:

    5 credits at the 30-day default, 10 at 14 days, 20 at 7 days, 50 at 3 days,
    150 at 1 day. A run that

    finds nothing costs nothing, and the baseline run is free for both kinds.


    **Rate limit.** Watch-management requests are limited to 10 requests per
    minute per API key.


    **Access.** Creating a watch is open to any authenticated API customer, and
    the 10-requests-per-minute

    limit is what bounds abuse. What is gated is the data underneath: a create
    is rejected with `403` when

    the key is not entitled to the dataset, or when `fields` or `track` name
    field groups the key may not

    receive. Contact info@crustdata.com to request access.
servers:
  - url: https://api.crustdata.com
    description: Production API server
security:
  - bearerAuth: []
tags:
  - name: Watch APIs
    description: Recurring feeds over the Crustdata datasets
  - name: Discovery Watches
    description: Watches that re-run a search filter and deliver newly matching records
  - name: Entity Watches
    description: >-
      Watches that monitor a supplied list of people or companies for field
      changes
  - name: Watch Runs
    description: Run history and per-run delivery detail, shared by both watch kinds
paths:
  /watch/{dataset}/search:
    get:
      tags:
        - Watch APIs
        - Discovery Watches
      summary: List your discovery watches
      description: >
        Returns your discovery watches for this dataset, newest first, as a bare
        JSON array. Each entry

        carries its all-time usage counters (`notifications_count`,
        `credits_consumed`,

        `last_notified_at`) alongside its definition.
      operationId: listDiscoveryWatches
      parameters:
        - $ref: '#/components/parameters/DatasetPath'
        - $ref: '#/components/parameters/ApiVersion'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/OffsetQuery'
      responses:
        '200':
          description: Your discovery watches for this dataset.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DiscoveryWatch'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/WatchForbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    DatasetPath:
      name: dataset
      in: path
      required: true
      description: The dataset the watch is built on.
      schema:
        type: string
        enum:
          - person
          - company
          - job
        example: person
    ApiVersion:
      name: x-api-version
      in: header
      required: true
      schema:
        type: string
        enum:
          - '2025-11-01'
        default: '2025-11-01'
        example: '2025-11-01'
      description: >
        API version to use. `2025-11-01` is the only accepted value. Send it on
        every call: it is

        enforced today on `POST /watch/{dataset}/search`, where a missing or
        unrecognized value returns

        `400`, and the other watch routes accept a request without it rather
        than relying on that.
    StatusQuery:
      name: status
      in: query
      required: false
      description: Return only watches in this state. Omit to return every state.
      schema:
        type: string
        enum:
          - active
          - paused
          - suspended
          - expired
          - cancelled
        example: active
    LimitQuery:
      name: limit
      in: query
      required: false
      description: >-
        Watches per page. Values above the maximum are clamped rather than
        rejected, as is a non-numeric value, which falls back to the default.
      schema:
        type: integer
        minimum: 1
        maximum: 500
        default: 100
        example: 50
    OffsetQuery:
      name: offset
      in: query
      required: false
      description: Number of watches to skip. Negative values are clamped to `0`.
      schema:
        type: integer
        minimum: 0
        default: 0
        example: 0
  schemas:
    DiscoveryWatch:
      type: object
      description: A discovery watch, as returned by create, get, list, and update.
      properties:
        id:
          type: integer
          description: The watch's id. Use it on every management and run-history path.
          example: 47609
        kind:
          type: string
          enum:
            - discovery
          example: discovery
        dataset:
          type: string
          enum:
            - person
            - company
            - job
          example: job
        api_version:
          type: string
          example: '2025-11-01'
        config_version:
          type: string
          description: Version of the stored config shape.
          example: '2025-11-01'
        status:
          type: string
          enum:
            - active
            - paused
            - suspended
            - expired
            - cancelled
          description: >
            Lifecycle state. `suspended` is set by the system, most often for an
            insufficient

            balance, and blocks status changes until it is resolved.
          example: active
        filters:
          description: The saved filter, as sent at creation.
          oneOf:
            - $ref: '#/components/schemas/FilterCondition'
            - $ref: '#/components/schemas/FilterConditionGroup'
        'on':
          type: array
          items:
            type: string
          example:
            - added
        sorts:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/SortSpec'
        fields:
          type: array
          nullable: true
          items:
            type: string
        config:
          $ref: '#/components/schemas/DiscoveryWatchConfig'
        notifications:
          type: array
          description: The configured channels. A stored channel secret is never returned.
          items:
            $ref: '#/components/schemas/NotificationChannel'
        created_at:
          type: string
          format: date-time
          example: '2026-07-16T03:16:38.351849Z'
        last_run_at:
          type: string
          format: date-time
          nullable: true
          description: When the watch last ran. `null` until the baseline run completes.
          example: '2026-08-04T05:32:47.000000Z'
        notifications_count:
          type: integer
          description: All-time count of records this watch has delivered.
          example: 128
        credits_consumed:
          type: number
          description: All-time credits this watch has spent.
          example: 64
        last_notified_at:
          type: string
          format: date-time
          nullable: true
          description: When this watch last delivered anything.
          example: '2026-08-04T05:32:47.000000Z'
    FilterCondition:
      type: object
      description: >
        One filter leaf. `field` and the operators are exactly those of the
        dataset's own search

        endpoint, so the Person, Company, and Job search references are the full
        catalog.
      required:
        - field
        - type
      properties:
        field:
          type: string
          description: >
            Dot-path of the field to filter on, for example

            `experience.employment_details.current.title` for a person or
            `job_details.title` for a

            job. Field names are unique across datasets, so a leaf naming
            another dataset's field is

            a valid cross-dataset condition rather than a mistake.
          example: experience.employment_details.current.title
        type:
          type: string
          description: >
            The comparison operator. Crustdata writes greater-or-equal as `=>`
            and less-or-equal as

            `=<`, not `>=` / `<=`.


            A cross-dataset leaf may not use a row-level negation operator
            (`!=`, `not_in`, `(!)`,

            `geo_exclude`): it would match subjects with some *other* matching
            row rather than

            subjects with none. List the values you do want instead.
          example: (.)
          enum:
            - '='
            - '!='
            - in
            - not_in
            - '>'
            - <
            - '=>'
            - '=<'
            - (.)
            - (!)
            - '[.]'
            - geo_distance
            - geo_exclude
        value:
          description: >
            The value to compare against. A scalar for `=`, `!=`, `>`, `<`,
            `=>`, `=<`, and the

            substring operators; an array for `in` and `not_in`; an object for
            the geo operators.

            Required for every operator except the null checks.
          example: Machine Learning Engineer
    FilterConditionGroup:
      type: object
      description: >-
        A group that combines conditions with AND or OR. Groups nest, so an
        `and` group can sit inside an `or` group's `conditions`.
      required:
        - op
        - conditions
      properties:
        op:
          type: string
          enum:
            - and
            - or
          description: How to combine `conditions`.
          example: and
        conditions:
          type: array
          minItems: 1
          description: The conditions to combine. Each item is a leaf or another group.
          items:
            oneOf:
              - $ref: '#/components/schemas/FilterCondition'
              - $ref: '#/components/schemas/FilterConditionGroup'
    SortSpec:
      type: object
      description: >-
        One sort key. Only indexed, sortable fields of the dataset may be sorted
        on; anything else returns `400` at create time.
      required:
        - field
        - order
      properties:
        field:
          type: string
          description: Dot-path of the field to sort by.
          example: metadata.date_added
        order:
          type: string
          enum:
            - asc
            - desc
          description: Sort direction.
          example: desc
    DiscoveryWatchConfig:
      type: object
      description: Schedule and per-run caps for a discovery watch.
      required:
        - trigger
      properties:
        trigger:
          $ref: '#/components/schemas/WatchTrigger'
        max_results_per_run:
          type: integer
          minimum: 1
          maximum: 1000
          default: 25
          description: >
            Most records to deliver in one run. The first, baseline run is
            always capped at 5

            regardless of this value.
          example: 25
        preferred_hour:
          type: integer
          minimum: 0
          maximum: 23
          nullable: true
          description: Hour of day, in UTC, to prefer for the run.
          example: 9
        expires_at:
          type: string
          format: date
          nullable: true
          description: Auto-expire date, `YYYY-MM-DD`. The watch stops running after it.
          example: '2027-01-01'
    NotificationChannel:
      description: >-
        One delivery channel. Every channel on a watch receives every
        notification.
      oneOf:
        - $ref: '#/components/schemas/WebhookChannel'
        - $ref: '#/components/schemas/SlackChannel'
        - $ref: '#/components/schemas/GoogleChatChannel'
        - $ref: '#/components/schemas/EmailChannel'
      discriminator:
        propertyName: type
        mapping:
          webhook:
            $ref: '#/components/schemas/WebhookChannel'
          slack:
            $ref: '#/components/schemas/SlackChannel'
          google_chat:
            $ref: '#/components/schemas/GoogleChatChannel'
          email:
            $ref: '#/components/schemas/EmailChannel'
    AuthErrorResponse:
      type: object
      description: >
        Authentication error payload. The message distinguishes the two
        failures: `Missing API key in

        request` when no `Authorization` header was sent, and `Invalid API key
        in request` when the

        Bearer token is not a valid key.
      required:
        - message
      example:
        message: Invalid API key in request
      properties:
        message:
          type: string
          description: Human-readable authentication error message.
          example: Invalid API key in request
    SimpleErrorResponse:
      type: object
      description: Error payload with a single human-readable message.
      required:
        - error
      example:
        error: Watch not found
      properties:
        error:
          type: string
          description: Human-readable description of what went wrong.
          example: Watch not found
    StructuredErrorResponse:
      type: object
      description: >-
        Structured error payload, used for rate-limit and API-version failures.
        The flatter `SimpleErrorResponse` shape is used elsewhere, so parse
        defensively.
      required:
        - error
      example:
        error:
          type: rate_limit_error
          message: >-
            Rate limit exceeded for this endpoint. Please write to
            gtm@crustdata.co.
          metadata: []
      properties:
        error:
          type: object
          required:
            - type
            - message
          properties:
            type:
              type: string
              description: Machine-readable error type identifier.
              example: rate_limit_error
            message:
              type: string
              description: Human-readable description of what went wrong.
              example: >-
                Rate limit exceeded for this endpoint. Please write to
                gtm@crustdata.co.
            metadata:
              type: array
              description: Extra context, empty on most errors.
              items:
                type: object
                additionalProperties: true
              example: []
    WatchTrigger:
      type: object
      description: How often the watch runs. Interval is the only trigger type today.
      required:
        - type
        - every_hours
      properties:
        type:
          type: string
          enum:
            - interval
          description: Trigger type.
          example: interval
        every_hours:
          type: integer
          minimum: 1
          description: Hours between runs, for example `1`, `6`, `24`, or `168`.
          example: 24
    WebhookChannel:
      type: object
      description: >-
        An HTTPS endpoint you control. Deliveries are signed, and a URL that
        resolves to a private, loopback, or link-local address is rejected.
      required:
        - type
        - url
      properties:
        type:
          type: string
          enum:
            - webhook
          example: webhook
        url:
          type: string
          format: uri
          description: Public `http(s)` URL to POST each notification to.
          example: https://your-app.com/webhooks/crustdata
        headers:
          type: object
          additionalProperties:
            type: string
          description: >-
            Extra headers to send with each delivery, for routing or
            authentication on your side.
          example:
            X-Watch-Name: ml-engineers-paris
    SlackChannel:
      type: object
      description: >-
        A Slack incoming webhook. The URL must be a genuine
        `https://hooks.slack.com/services/...` webhook; any other URL fails
        delivery.
      required:
        - type
        - webhook_url
      properties:
        type:
          type: string
          enum:
            - slack
          example: slack
        webhook_url:
          type: string
          format: uri
          example: https://hooks.slack.com/services/T000/B000/XXXX
    GoogleChatChannel:
      type: object
      description: A Google Chat incoming webhook.
      required:
        - type
        - url
      properties:
        type:
          type: string
          enum:
            - google_chat
          example: google_chat
        url:
          type: string
          format: uri
          example: https://chat.googleapis.com/v1/spaces/AAAA/messages?key=...
    EmailChannel:
      type: object
      description: One or more email recipients.
      required:
        - type
        - to
      properties:
        type:
          type: string
          enum:
            - email
          example: email
        to:
          type: array
          minItems: 1
          items:
            type: string
            format: email
          description: Recipient addresses.
          example:
            - you@company.com
  responses:
    Unauthorized:
      description: The API key is missing or not valid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuthErrorResponse'
          examples:
            invalid_api_key:
              summary: Bearer token present but not a valid key
              value:
                message: Invalid API key in request
            missing_api_key:
              summary: No Authorization header at all
              value:
                message: Missing API key in request
    WatchForbidden:
      description: >
        The key is not entitled to this dataset, or to a field group the request
        names. The watch

        surface itself is open to any authenticated API customer.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SimpleErrorResponse'
          example:
            error: >-
              You do not have access to the person dataset. Contact
              info@crustdata.com to request access.
    RateLimited:
      description: >
        Too many watch requests. The per-endpoint limit is 10 requests per
        minute per API key, which is

        what bounds bursty create and update loops. Steady use is unaffected.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/StructuredErrorResponse'
          example:
            error:
              type: rate_limit_error
              message: >-
                Rate limit exceeded for this endpoint. Please write to
                gtm@crustdata.co.
              metadata: []
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key passed as a Bearer token in the Authorization header.

````

## Related topics

- [List watch runs](/api-reference/watch-apis/list-a-watchs-runs.md)
- [Create a discovery watch](/api-reference/watch-apis/create-a-discovery-watch.md)
- [Get a discovery watch](/api-reference/watch-apis/get-one-discovery-watch.md)
- [Person Discovery Watcher](/watcher-docs/person/discovery.md)
- [Company Discovery Watcher](/watcher-docs/company/discovery.md)
