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

# Preview Watch

> Dry-run a watch query: get a match count without creating a watch

## Overview

Returns the number of trademarks that would have alerted if this query had been a live watch
over the last `trial_window_days` (default 7). Uses the same evaluation logic as a live watch,
so the count is a faithful preview, not a separate query engine. Use it before
[Create Watch](/api-reference/monitoring/watches/create) to estimate volume and tune
`strategies` / `min_match_tier` for similarity watches.

Requires the `portfolios:manage` scope.

<Note>
  Preview is a read-shaped operation, so the `Idempotency-Key` header is not required. Sending
  one, as in the example below, is always safe.
</Note>

## Body Parameters

<ParamField body="query" type="object" required>
  Same DSL as [Create Watch](/api-reference/monitoring/watches/create), see
  [the query reference](/guides/monitoring/watches#the-query-dsl). ID-bearing filters
  (`filters.trademarkIds`, `filters.ownerId`, ...) accept the same `tm_*` / `own_*` prefixed
  forms as create.
</ParamField>

<ParamField body="trial_window_days" type="integer">
  Backtest window in days (1-365). Default 7.
</ParamField>

<ParamField body="count_only" type="boolean">
  Skip the matching marks and return just `estimated_match_count`. Default `false`.
</ParamField>

<ParamField body="result_limit" type="integer">
  Page size for `results` (1-50). Default 20. Ignored when `count_only` is `true`.
</ParamField>

## Response

<ResponseField name="object" type="string">Always `"watch_preview"`.</ResponseField>
<ResponseField name="estimated_match_count" type="integer">Trademarks that would have alerted in the trial window.</ResponseField>
<ResponseField name="results" type="array">A page of the actual matching trademarks, in the same summary shape as [search results](/api-reference/trademarks/list-trademarks). Omitted when `count_only` is `true`.</ResponseField>
<ResponseField name="has_more" type="boolean">Whether more matches exist beyond `results`. Omitted when `count_only` is `true`.</ResponseField>
<ResponseField name="result_limit" type="integer">Effective page size used for `results`. Omitted when `count_only` is `true`.</ResponseField>

<ResponseField name="estimate_basis" type="string">
  Present only when `estimated_match_count` is an upper bound rather than an exact count (the
  value is `"candidacy_upper_bound"`). This happens when the underlying scan is large enough to
  hit the server-side cap, or the time budget runs out after some matches were already found.
  Absent when the count is exact.
</ResponseField>

<ResponseField name="trial_window_days" type="integer">Echo of the requested window.</ResponseField>
<ResponseField name="request_id" type="string">Request identifier.</ResponseField>

## Latency and limits

Preview runs synchronously with a server-side time budget of about 20 seconds. `class`, `mark`,
and `owner` previews typically complete in a few seconds; `similarity` previews over broad
scopes and long windows are the heaviest and can approach the budget.

* If the budget runs out after some matches were found, the response is a `200` with a partial
  count and `estimate_basis: "candidacy_upper_bound"`.
* If it runs out before any usable result exists, the response is a `504` (see Errors).
* Concurrent previews are limited per organization; exceeding the limit returns `429` with a
  `Retry-After` header. See [Rate limits](/api-reference/rate-limits) for header semantics.

## Errors

| Status | `type`              | When                                                                                                                                                                                                   |
| ------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 400    | `validation_error`  | Invalid `query` (see [Create Watch](/api-reference/monitoring/watches/create))                                                                                                                         |
| 413    | `payload_too_large` | `query` payload exceeds 256 KB                                                                                                                                                                         |
| 429    | `rate_limited`      | Another preview is already running for your organization, or the server's preview capacity is saturated. Honor `Retry-After` (about 20 seconds); the SDK retries automatically.                        |
| 504    | `preview_timeout`   | The time budget expired before any usable result existed. The response carries `retryable: false`; narrow the query (fewer offices, shorter `trial_window_days`, tighter filters) instead of retrying. |

```json 504 preview_timeout theme={null}
{
  "error": {
    "type": "preview_timeout",
    "title": "Preview Timeout",
    "status": 504,
    "detail": "The preview could not produce a result within the server-side time budget.",
    "suggestion": "Narrow the watch query, add office or jurisdiction filters, reduce trial_window_days, or scope filters.trademarkIds, and retry.",
    "retryable": false
  },
  "request_id": "req_8mQ2vXpL"
}
```

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.signa.so/v1/watches/preview" \
    -H "Authorization: Bearer sig_YOUR_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: preview-owner-watch-2026-06-12" \
    -d '{
      "query": {
        "version": "v2",
        "filters": { "ownerId": "own_7pQmX3Lv" }
      },
      "trial_window_days": 30
    }'
  ```

  ```typescript TypeScript theme={null}
  import { Signa } from "@signa-so/sdk";
  const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });

  const preview = await signa.watches.preview({
    query: {
      version: "v2",
      filters: { ownerId: "own_7pQmX3Lv" },
    },
    trial_window_days: 30,
  });
  console.log(`${preview.estimated_match_count} alerts in the last 30 days`);
  ```
</CodeGroup>

<ResponseExample>
  ```json Exact count theme={null}
  {
    "object": "watch_preview",
    "estimated_match_count": 17,
    "trial_window_days": 30,
    "request_id": "req_8mQ2vXpL"
  }
  ```

  ```json Upper-bound estimate theme={null}
  {
    "object": "watch_preview",
    "estimated_match_count": 50000,
    "estimate_basis": "candidacy_upper_bound",
    "trial_window_days": 30,
    "request_id": "req_4nRvXq2T"
  }
  ```
</ResponseExample>

## Related Endpoints

* [Create Watch](/api-reference/monitoring/watches/create) - turn a preview into a live watch
* [Bulk Create Watches](/api-reference/monitoring/watches/bulk) - create up to 100 watches at once
* [Rate limits](/api-reference/rate-limits) - request and concurrency limits
