Watch Attestation
curl --request GET \
--url https://api.signa.so/v1/watches/{id}/attestation \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.signa.so/v1/watches/{id}/attestation"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signa.so/v1/watches/{id}/attestation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.signa.so/v1/watches/{id}/attestation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/watches/{id}/attestation"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.signa.so/v1/watches/{id}/attestation")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/watches/{id}/attestation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"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"
}
{
"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`."
}
}
Watches
Watch Attestation
Fetch the monthly proof-of-monitoring record for a watch, as verifiable JSON or a filable PDF
GET
/
v1
/
watches
/
{id}
/
attestation
Watch Attestation
curl --request GET \
--url https://api.signa.so/v1/watches/{id}/attestation \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.signa.so/v1/watches/{id}/attestation"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signa.so/v1/watches/{id}/attestation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.signa.so/v1/watches/{id}/attestation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/watches/{id}/attestation"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.signa.so/v1/watches/{id}/attestation")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/watches/{id}/attestation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"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"
}
{
"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`."
}
}
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 samecontent_hash.
Read-only: calling it never changes anything.
Requires the portfolios:manage scope.
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.Path Parameters
string
required
Watch ID (
wat_*).Query Parameters
string
UTC calendar month as
YYYY-MM. Defaults to the previous (most recently closed) month.'json' | 'pdf'
Response format. Defaults to
json. Use pdf for the business record. An explicit format
wins over the Accept header.'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.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
string
Always
watch_attestation.string
Artifact schema version (e.g.
2026-08-01). Bumped on any additive field change.object
The monitoring instruction the record attests to.
Show watch
Show watch
string
Watch ID (
wat_*).string
Display only. Excluded from
content_hash, since it is mutable via PATCH.string
Stable
sha256 hash of the watch query and trigger events.'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.
string[]
Lifecycle events this watch fires on.
boolean
true when the configuration changed during the period. epochs_in_period lists the
evaluation epochs seen.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.integer[]
Evaluation epochs observed in the period. Present when more than one occurred.
object
object[]
One entry per office in the watch’s scope.
Show offices[]
Show offices[]
string
Uppercase ST.3 code (e.g.
US, EM).string
Full office name.
'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. |
integer
Evaluations performed for this office.
string[]
Sync runs the evaluations consumed.
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.
integer
Matches found.
integer
Alerts produced.
string | null
Start of the office-data horizon covered.
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.'source_dates' | 'date_range' | 'run_completed' | null
How the coverage horizon was derived.
object[]
Disclosed coverage gaps. See Coverage gaps.
'consistent' | 'mismatch'
Cross-check of the recorded alert counts against the stored alert rows for the period.
mismatch is disclosed rather than silently reconciled.string
The plain-language attestation, including the limit of what it certifies.
string
Version of the internal freshness-target table used to decide what counted as a gap.
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.string
When this copy was produced. Excluded from
content_hash.string
sha256 over the canonical artifact. See Verifying a filed record.string
Request identifier.
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.string
When coverage first went stale.
string
When coverage recovered, or the period end if it never did.
'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.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.- 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
nullcoverage_through, never presented as covered.
Unsupported offices
If a watch is scoped to an office Signa does not ingest, that office appears withstatus: "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.
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.Retention
Attestations are available for closed months within the last 25 months. Beyond that, the backing evaluation receipts have aged out and the endpoint returns410 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
# 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
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);
}
}
{
"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"
}
{
"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`."
}
}
Related Endpoints
- Watch Diagnostics - explain a single expected alert
- Retrieve Watch - the watch this record attests to
- Attestations guide - how firms use the artifact
- Monitoring status guide - live coverage, as opposed to the monthly record