> ## 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.

# Watch Attestation

> Fetch the monthly proof-of-monitoring record for a watch, as verifiable JSON or a filable PDF

## Overview

A filable, monthly record that a watch was actually evaluated during a period, the office-data
horizon it covered, and the outcome, including the negative outcome. It is the artifact a firm
keeps on file to show that a monitoring instruction was in force and was executed.

The artifact is computed **deterministically** from the evaluation receipts recorded at the time,
so re-fetching a closed period months later produces the same bytes and the same `content_hash`.
Read-only: calling it never changes anything.

Requires the `portfolios:manage` scope.

<Note>
  **What it certifies, and what it does not.** This record certifies that evaluation occurred against
  the stated data horizons. It does **not** certify that every relevant mark was surfaced, since
  recall is bounded by office coverage and match strategy. That distinction is written into the
  `statement` field of every artifact and printed on the PDF.
</Note>

## Path Parameters

<ParamField path="id" type="string" required>
  Watch ID (`wat_*`).
</ParamField>

## Query Parameters

<ParamField query="period" type="string">
  UTC calendar month as `YYYY-MM`. Defaults to the previous (most recently closed) month.
</ParamField>

<ParamField query="format" type="'json' | 'pdf'">
  Response format. Defaults to `json`. Use `pdf` for the business record. An explicit `format`
  wins over the `Accept` header.
</ParamField>

<ParamField query="partial" type="'true' | 'false'">
  Set `true` to get an interim artifact for the current, still-open month. The result carries
  `period.partial: true` and its figures can still change. Default `false`.
</ParamField>

## The PDF business record

Pass `?format=pdf`, or send `Accept: application/pdf`. The response is a PDF attachment named
`{watch-name}-{YYYY-MM}-attestation.pdf`.

The PDF is rendered from the same artifact as the JSON, so the two never disagree. It leads with
the summary figures and the attested statement, then the per-office coverage table and any
disclosed gaps, then the configuration and integrity hash. The JSON is the copy you verify
against; the PDF is the copy you file.

## Response

<ResponseField name="object" type="string">Always `watch_attestation`.</ResponseField>

<ResponseField name="schema_version" type="string">
  Artifact schema version (e.g. `2026-08-01`). Bumped on any additive field change.
</ResponseField>

<ResponseField name="watch" type="object">
  The monitoring instruction the record attests to.

  <Expandable title="watch">
    <ResponseField name="id" type="string">Watch ID (`wat_*`).</ResponseField>

    <ResponseField name="name" type="string">
      Display only. **Excluded** from `content_hash`, since it is mutable via `PATCH`.
    </ResponseField>

    <ResponseField name="query_fingerprint" type="string">
      Stable `sha256` hash of the watch query and trigger events.
    </ResponseField>

    <ResponseField name="fingerprint_basis" type="'current_configuration'">
      What the fingerprint describes: the configuration as it exists **when you fetch**. A true
      evaluated-time snapshot needs configuration history that is not stored yet, so the two flags
      below keep this honest.
    </ResponseField>

    <ResponseField name="trigger_events" type="string[]">Lifecycle events this watch fires on.</ResponseField>

    <ResponseField name="configuration_changed_in_period" type="boolean">
      `true` when the configuration changed **during** the period. `epochs_in_period` lists the
      evaluation epochs seen.
    </ResponseField>

    <ResponseField name="configuration_changed_since_period" type="boolean">
      `true` when the configuration changed **after** the period closed, so the fingerprint no
      longer describes the configuration that was in force. Generation-time fact, excluded from
      `content_hash`.
    </ResponseField>

    <ResponseField name="epochs_in_period" type="integer[]">
      Evaluation epochs observed in the period. Present when more than one occurred.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="period" type="object">
  <Expandable title="period">
    <ResponseField name="start" type="string">Inclusive UTC start of the month.</ResponseField>

    <ResponseField name="end" type="string">
      **Exclusive** UTC end (midnight on the first of the next month).
    </ResponseField>

    <ResponseField name="partial" type="boolean">
      `true` for an interim artifact of a still-open month. Figures can still change.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="offices" type="object[]">
  One entry per office in the watch's scope.

  <Expandable title="offices[]">
    <ResponseField name="office_code" type="string">Uppercase ST.3 code (e.g. `US`, `EM`).</ResponseField>
    <ResponseField name="office_name" type="string">Full office name.</ResponseField>

    <ResponseField name="status" type="'evaluated' | 'no_evaluations' | 'unsupported'">
      | Value            | Meaning                                                                                                                                                                      |
      | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
      | `evaluated`      | A covered office with real evaluation claims.                                                                                                                                |
      | `no_evaluations` | A covered office with **zero** evaluations in the period: zero counts, no coverage claims, and a full-period gap. An un-evaluated month never reads as a clean silent month. |
      | `unsupported`    | An in-scope office Signa does not ingest. **No** evaluation fields are returned at all.                                                                                      |
    </ResponseField>

    <ResponseField name="evaluations_count" type="integer">Evaluations performed for this office.</ResponseField>
    <ResponseField name="sync_runs_evaluated" type="string[]">Sync runs the evaluations consumed.</ResponseField>

    <ResponseField name="changes_evaluated" type="integer">
      Volume of office change weighed **against your query** this period. Not the size of the
      office register, and not a claim about how many records exist.
    </ResponseField>

    <ResponseField name="match_count" type="integer">Matches found.</ResponseField>
    <ResponseField name="alerts_emitted" type="integer">Alerts produced.</ResponseField>
    <ResponseField name="coverage_from" type="string | null">Start of the office-data horizon covered.</ResponseField>

    <ResponseField name="coverage_through" type="string | null">
      Office **data** time evaluations reached, frozen on the receipt at evaluation time. `null`
      on receipts predating coverage snapshots, which are disclosed as a gap rather than presented
      as covered.
    </ResponseField>

    <ResponseField name="coverage_basis" type="'source_dates' | 'date_range' | 'run_completed' | null">
      How the coverage horizon was derived.
    </ResponseField>

    <ResponseField name="gaps" type="object[]">
      Disclosed coverage gaps. See [Coverage gaps](#coverage-gaps).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="totals" type="object">
  <Expandable title="totals">
    <ResponseField name="evaluations" type="integer">Evaluations across all offices.</ResponseField>
    <ResponseField name="alerts_emitted" type="integer">Alerts across all offices.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="reconciliation" type="'consistent' | 'mismatch'">
  Cross-check of the recorded alert counts against the stored alert rows for the period.
  `mismatch` is disclosed rather than silently reconciled.
</ResponseField>

<ResponseField name="statement" type="string">
  The plain-language attestation, including the limit of what it certifies.
</ResponseField>

<ResponseField name="slo_reference" type="string">
  Version of the internal freshness-target table used to decide what counted as a gap.
</ResponseField>

<ResponseField name="watch_status_at_generation" type="string">
  Present (`paused` or `disabled`) when the watch is not active **at generation time**. Pause
  history within the period is not reconstructable today. Excluded from `content_hash`.
</ResponseField>

<ResponseField name="generated_at" type="string">When this copy was produced. Excluded from `content_hash`.</ResponseField>

<ResponseField name="content_hash" type="string">
  `sha256` over the canonical artifact. See [Verifying a filed record](#verifying-a-filed-record).
</ResponseField>

<ResponseField name="request_id" type="string">Request identifier.</ResponseField>

## Coverage gaps

A gap is an interval where the office-data coverage the watch had evaluated through fell behind
the internal freshness target for that office. Gaps are reconstructed from the receipts, not
recorded by hand.

<ResponseField name="from" type="string">When coverage first went stale.</ResponseField>

<ResponseField name="through" type="string">
  When coverage recovered, or the period end if it never did.
</ResponseField>

<ResponseField name="reason" type="'office_lagging' | 'evaluation_failed'">
  `office_lagging` means coverage was stale beyond the target. `evaluation_failed` is reserved for
  a future version: failed evaluations write no receipt, so they are not reconstructed as gaps
  today.
</ResponseField>

<ResponseField name="resolved" type="boolean">
  `true` when coverage caught back up **inside** the period. `false` means it was still behind
  when the period closed. That is a statement about this period only, not a claim that it stayed
  behind afterwards.
</ResponseField>

Gap disclosure is **permanent**. Once a period's artifact records a gap it records it forever,
even after coverage recovers, because it is a fact about what happened.

Two shapes worth knowing:

* A covered office with **zero evaluations** carries a single gap spanning the whole period.
* Evaluations recorded **before coverage snapshots existed** cannot state what horizon they
  covered, so they are disclosed as incomplete coverage evidence with a `null` `coverage_through`,
  never presented as covered.

## Unsupported offices

If a watch is scoped to an office Signa does not ingest, that office appears with
`status: "unsupported"` and **no evaluation claims at all**. Signa will never render a clean,
zero-alert attestation for an office it does not cover, because that would read as "we looked and
found nothing" when the truth is "we do not cover this office yet".

If **every** office in the scope is unsupported, the endpoint returns `422
attestation_unsupported_scope` rather than an empty artifact.

## Verifying a filed record

`content_hash` is a `sha256` over the canonical, sorted-key artifact, excluding the fields that
legitimately differ between two fetches of the same period: `generated_at`, `request_id`,
`content_hash` itself, `watch_status_at_generation`, `watch.name`, and
`watch.configuration_changed_since_period`.

To verify a filed copy, re-fetch the same closed period and compare hashes. A match proves the
figures were not altered after issue.

This proves **integrity**, not third-party **authenticity**. Signed and RFC 3161 timestamped
documents are on the roadmap.

<Tip>
  Fetch and file the artifact promptly after the month closes, before changing the watch. A filed
  copy with both `configuration_changed_*` flags `false` pins the fingerprint to the period
  unambiguously.
</Tip>

## Retention

Attestations are available for closed months within the last **25 months**. Beyond that, the
backing evaluation receipts have aged out and the endpoint returns `410 attestation_expired`.

## Errors

| Status | `type`                          | When                                                                                     |
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------- |
| 400    | `validation_error`              | `period` is not a valid `YYYY-MM` label                                                  |
| 403    | `forbidden`                     | Caller lacks `portfolios:manage`                                                         |
| 404    | `not_found`                     | The watch doesn't exist or belongs to another org                                        |
| 410    | `attestation_expired`           | The period is beyond the 25-month retention window                                       |
| 422    | `attestation_period_open`       | The period is the current, still-open month. Pass `partial=true` for an interim artifact |
| 422    | `attestation_unsupported_scope` | Every office in the watch's scope is one Signa does not ingest                           |

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Previous closed month, JSON
  curl "https://api.signa.so/v1/watches/wat_8kLm2nPq/attestation" \
    -H "Authorization: Bearer sig_YOUR_KEY"

  # A specific month, as the filable PDF
  curl "https://api.signa.so/v1/watches/wat_8kLm2nPq/attestation?period=2026-07&format=pdf" \
    -H "Authorization: Bearer sig_YOUR_KEY" \
    -o july-attestation.pdf
  ```

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

  const record = await signa.watches.attestation("wat_8kLm2nPq", { period: "2026-07" });
  console.log(record.statement);

  // Any gap the period disclosed, per office.
  for (const office of record.offices) {
    for (const gap of office.gaps ?? []) {
      console.log(office.office_code, gap.from, gap.through, gap.resolved);
    }
  }
  ```
</CodeGroup>

<ResponseExample>
  ```json Closed month with a disclosed gap theme={null}
  {
    "object": "watch_attestation",
    "schema_version": "2026-08-01",
    "watch": {
      "id": "wat_8kLm2nPq",
      "name": "ACME Corp, class 9 similarity watch",
      "query_fingerprint": "sha256:9f2c41ab7e5d0c3388a1b6ee42d9f70c1a4b8e5537cc9d21e0f6a4b3c8d71e59",
      "fingerprint_basis": "current_configuration",
      "trigger_events": ["trademark.created", "trademark.published"],
      "configuration_changed_in_period": false,
      "configuration_changed_since_period": false
    },
    "period": {
      "start": "2026-07-01T00:00:00.000Z",
      "end": "2026-08-01T00:00:00.000Z",
      "partial": false
    },
    "offices": [
      {
        "office_code": "US",
        "office_name": "United States Patent and Trademark Office",
        "status": "evaluated",
        "evaluations_count": 31,
        "sync_runs_evaluated": ["018f9b2e-0000-7000-8000-000000000001"],
        "changes_evaluated": 412083,
        "match_count": 2,
        "alerts_emitted": 1,
        "coverage_from": "2026-06-30T23:59:59.999Z",
        "coverage_through": "2026-07-31T23:59:59.999Z",
        "coverage_basis": "source_dates",
        "gaps": [
          {
            "from": "2026-07-11T00:00:00.000Z",
            "through": "2026-07-14T00:00:00.000Z",
            "reason": "office_lagging",
            "resolved": true
          }
        ]
      },
      {
        "office_code": "JP",
        "office_name": "Japan Patent Office",
        "status": "unsupported"
      }
    ],
    "totals": { "evaluations": 31, "alerts_emitted": 1 },
    "reconciliation": "consistent",
    "statement": "This watch was evaluated 31 times during the period, covering office data through the per-office coverage timestamps stated above. 1 alert was produced. Coverage gaps, if any, are disclosed per office. This attestation certifies that evaluation occurred against the stated data horizons. It does not certify that every relevant mark was surfaced.",
    "slo_reference": "2026-08-01",
    "generated_at": "2026-08-01T09:00:00.000Z",
    "content_hash": "sha256:4d1e8a7c93b25f60ae1c7d4488f302b95e6a1cc07df3b28e94a6501fbb27c3d1",
    "request_id": "req_2mR8vNkT"
  }
  ```

  ```json Period still open theme={null}
  {
    "request_id": "req_7hTn4kLp",
    "error": {
      "type": "attestation_period_open",
      "title": "Attestation period is still open",
      "detail": "The period 2026-08 is the current (in-progress) UTC month. A final attestation is only produced for closed calendar months.",
      "retryable": false,
      "suggestion": "Request a previous (closed) month, or pass `partial=true` to get an interim artifact marked `\"partial\": true`."
    }
  }
  ```
</ResponseExample>

## Related Endpoints

* [Watch Diagnostics](/api-reference/monitoring/watches/diagnostics) - explain a single expected alert
* [Retrieve Watch](/api-reference/monitoring/watches/retrieve) - the watch this record attests to
* [Attestations guide](/guides/monitoring/attestations) - how firms use the artifact
* [Monitoring status guide](/guides/monitoring/monitoring-status) - live coverage, as opposed to the monthly record
