Skip to main content
GET
/
v1
/
watches
/
{id}
/
diagnostics
curl "https://api.signa.so/v1/watches/wat_01HK7M.../diagnostics?trademark_id=tm_01HK7N..." \
  -H "Authorization: Bearer $SIGNA_API_KEY"
{
  "watch_id": "<string>",
  "trademark_id": "<string>",
  "office_code": "<string>",
  "evaluated": true,
  "office_in_scope": true,
  "candidacy_passed": true,
  "trigger_event_type": {},
  "trigger_event_in_filter": true,
  "opensearch_score": {},
  "score_threshold": {},
  "alert_fired": true,
  "reason": "<string>",
  "delivery_mode_effective": {},
  "lease_state": {},
  "evaluation_epoch": 123,
  "replay_epoch_origin": {},
  "last_relevant_sync_run": {
    "id": "<string>",
    "office_code": "<string>",
    "completed_at": {},
    "search_indexed_at": {}
  },
  "outbox_event_id": {},
  "opposition": {
    "must_act_by": {},
    "rule_source": {},
    "rule_version": {},
    "window_status": {}
  },
  "data_window": {
    "trademark_changes_retention_days": 123,
    "outbox_retention_days": 123,
    "indexing_status_retention_days": 123,
    "deliveries_retention_days": 123,
    "alerts_retention_days": 123,
    "diagnostic_freshness_horizon_days": 123
  },
  "request_id": "<string>"
}

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.

Overview

Self-service debugging for the question every monitoring customer eventually asks: “I expected an alert for this trademark. Why didn’t I get one?” Returns an 11-field, fully-explained trace of how Signa’s evaluator saw the trademark relative to this watch, walking from candidacy through trigger-event filtering through match outcome through delivery-mode resolution. When an alert was fired, the same response surfaces the cross-system trace IDs you need to correlate against your webhook receiver logs. Read-only. The endpoint never writes; it surfaces fields the evaluator and dispatchers already persisted. Required scope: portfolios:manage.

Path Parameters

id
string
required
Watch ID (wat_*).

Query Parameters

trademark_id
string
required
Trademark ID (tm_*) to evaluate against this watch. Cross-org IDs return 404 (info-disclosure prevention).

Response

watch_id
string
Echoed watch ID (wat_*).
trademark_id
string
Echoed trademark ID (tm_*).
office_code
string
Office that issued the trademark (lowercase ISO-style code, e.g. uspto, euipo).
evaluated
boolean
true if the watch evaluator processed this trademark in the current retention window. false either because the trademark wasn’t in candidacy, or because the relevant provenance has aged out of the retention window (see data_window below). When false, reason explains why.
office_in_scope
boolean
true if this watch’s filters include this trademark’s office. Watch + office routing happens via watch_office_checkpoints; if the checkpoint is missing or superseded_at is set, this is false.
candidacy_passed
boolean
true if a trademark_changes row exists for this trademark within the retention window. Candidacy is a prerequisite for evaluation; if no change was recorded the evaluator never saw the mark.
trigger_event_type
string | null
The lifecycle event derived for the matched change (trademark.created, trademark.updated, trademark.status_changed, etc.). When an alert was fired this is the frozen value from watch_alerts.event_type; otherwise it’s derived from the most recent trademark_changes row.
trigger_event_in_filter
boolean
true if trigger_event_type is allowed by the watch’s query.trigger_events filter. When false, the evaluator silently dropped the candidate — that’s the answer to “why no alert”.
opensearch_score
number | null
The OpenSearch relevance score at evaluation time, when applicable. Currently always null — the evaluator does not persist the per-trademark score on the alert row. Documented gap; will populate on a future schema bump.
score_threshold
number | null
The watch’s configured query.score_threshold (0..1) for similarity watches. null for non-similarity watches.
alert_fired
boolean
true if a watch_alerts row exists for this (watch, trademark) pair. When true, outbox_event_id is the cross-system trace handle.
reason
string
Human-readable explanation for the outcome. Walked in this order:
  1. "alert fired" — an alert row exists.
  2. "watch does not include office {code}" — checkpoint missing/superseded.
  3. "trademark evaluated more than {N} days ago; provenance no longer available" — past the diagnostic freshness horizon.
  4. "trademark not in candidacy window for sync_run {id}" — no recent trademark_changes row.
  5. "trigger event {type} not in watch.trigger_events" — change exists but the event type is filtered out.
  6. "score {n} below threshold {t}" — similarity match below threshold (only fires when both are populated).
  7. "would alert but rolled into digest" — the watch’s effective delivery mode resolved to digest; alert is queued for the digest job.
  8. "no matching reason available" — fallback; surface to support if you see it.
delivery_mode_effective
'per_alert' | 'digest' | null
Resolved delivery mode using the same logic as the evaluator. For digest_above_threshold this depends on the trailing 24h alert volume, so the value is “current effective” not “effective at evaluation time” — documented in the API contract.
lease_state
'held' | 'released' | 'abandoned' | 'epoch_raced' | 'cas_lost' | null
Best-effort classification of the per-(watch, office) evaluator lease. held is unambiguous (active lease started < 15min ago); epoch_raced indicates the evaluator’s evaluation_epoch_seen lags behind the watch’s current epoch (replay race); released is the default post-iteration state. abandoned / cas_lost are heuristic hints, not guarantees.
evaluation_epoch
integer
The watch’s current evaluation_epoch. Bumped by POST /v1/watches/{id}/replay.
replay_epoch_origin
integer | null
When the alert was emitted under a replay-bumped epoch, this is the alert’s frozen evaluation_epoch. null when the watch was never replayed (epoch=0) or no alert exists.
last_relevant_sync_run
object | null
The sync_runs row referenced by the watch+office checkpoint’s last_evaluated_sync_run_id.
outbox_event_id
string | null
The event_outbox UUID emitted alongside the alert. Cross-references the webhook-id on delivery audit rows under GET /v1/webhooks//deliveries. null when no alert fired.
opposition
object | null
Computed opposition-window state for this trademark. null when the trademark has no publication_date_first or no rule applies for the jurisdiction/route.
data_window
object
Retention horizons for the data this endpoint reads. Past these horizons the corresponding fields cannot be reconstructed and reason will surface “provenance no longer available”.
request_id
string
Request identifier.

Errors

  • 400trademark_id query parameter missing.
  • 403 — caller lacks portfolios:manage.
  • 404 — watch does not exist, belongs to another org, the trademark does not exist, or this trademark is out of the watch’s office scope and no alert was ever produced for the pair. The endpoint deliberately does not distinguish between these cases (info-disclosure prevention).

Retention

trademark_changes are retained for 90 days; webhook_deliveries for 30 days. Diagnostics queries past the 90-day horizon return evaluated=false with reason explaining the freshness limit.

Authentication

Standard API key via Authorization: Bearer $SIGNA_API_KEY. Org-scoped: the watch must belong to the calling org.
curl "https://api.signa.so/v1/watches/wat_01HK7M.../diagnostics?trademark_id=tm_01HK7N..." \
  -H "Authorization: Bearer $SIGNA_API_KEY"

See also