Skip to main content
A complete, copy-pasteable path for the most common monitoring setup: “tell me about new USPTO filings in my Nice class.” Four steps: preview the volume, create the watch, register a webhook, add a polling fallback. Everything below needs an API key with the portfolios:manage scope.

1. Preview the volume

Dry-run the query before going live. Scope to the US with filters.jurisdictions: ["US"] (equivalently filters.offices: ["uspto"] — jurisdictions are auto-translated to offices at create time):
curl -X POST "https://api.signa.so/v1/watches/preview" \
  -H "Authorization: Bearer $SIGNA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: preview-us-class9-2026-06-12" \
  -d '{
    "query": {
      "version": "v1",
      "filters": { "niceClasses": [9], "jurisdictions": ["US"] }
    },
    "trial_window_days": 7
  }'
{
  "object": "watch_preview",
  "estimated_match_count": 312,
  "trial_window_days": 7,
  "request_id": "req_..."
}
~312 alerts/week is a real feed. If the count is overwhelming, narrow with trigger_events: ["trademark.created"] (new filings only — drops the update/status churn) before creating. See Preview Watch for the estimate_basis / timeout semantics on heavier queries.

2. Create the watch

curl -X POST "https://api.signa.so/v1/watches" \
  -H "Authorization: Bearer $SIGNA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-us-class9-watch-001" \
  -d '{
    "name": "US class 9 — new filings",
    "watch_type": "class",
    "query": {
      "version": "v1",
      "filters": { "niceClasses": [9], "jurisdictions": ["US"] },
      "trigger_events": ["trademark.created"]
    }
  }'
The response is the Watch object — save its id (wat_*). The watch is active immediately and evaluates on every USPTO ingestion sync. Mutating calls like this one require the Idempotency-Key header.
When do alerts arrive? USPTO ingest runs daily at 01:01 UTC (with 05:01 / 13:01 UTC retry rails), so a new US filing typically alerts within ~24 hours of USPTO’s daily file publication. Webhook delivery itself takes seconds after detection. See Known beta limitations.

3. Register a webhook (push)

curl -X POST "https://api.signa.so/v1/webhooks" \
  -H "Authorization: Bearer $SIGNA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-us-class9-webhook-001" \
  -d '{
    "url": "https://alerts.example.com/signa",
    "description": "US class 9 alerts",
    "enabled_events": ["alert.created"]
  }'
Store the returned secret immediately — it is shown once. Each delivery is an HMAC-signed POST whose data.trademark_id you can pass straight to GET /v1/trademarks/{id}:
{
  "type": "alert.created",
  "id": "alt_...",
  "timestamp": "2026-06-12T01:14:09.412Z",
  "data": {
    "alert_id": "alt_...",
    "watch_id": "wat_...",
    "trademark_id": "tm_...",
    "trademark_record_id": "tm_...",
    "event_type": "trademark.created",
    "evaluation_epoch": 0,
    "content_version": 1,
    "severity": "normal",
    "must_act_by": "2026-07-13T03:59:59.999Z",
    "opposition_window_status": "open",
    "source_data_hash": "sha256:..."
  }
}
Verify signatures on every delivery (see Verify webhook signatures) and dedupe by the webhook-id header. No receiver yet? Use a tunnel or request-bin pattern to develop against real deliveries.

4. Add a polling fallback (pull)

Webhooks deliver in seconds but receivers go down. A daily reconciliation pass over the watch’s alerts catches anything you missed:
curl "https://api.signa.so/v1/watches/wat_.../alerts?limit=100" \
  -H "Authorization: Bearer $SIGNA_API_KEY"
Compare the returned alert IDs against what your receiver recorded; fetch any gaps with POST /v1/alerts/lookup or process them directly from the list response. Page with the pagination.cursor until has_more is false. For the full reconciliation pattern (and replay handling), see Handling alerts.

Variations

  • US filings for a specific competitor: watch_type: "owner" with filters: { ownerId: "own_...", jurisdictions: ["US"] }.
  • Confusingly-similar US filings: watch_type: "similarity" with q: "yourmark", score_threshold: 0.85, and filters: { jurisdictions: ["US"] }.
  • More jurisdictions later: PATCH the watch with a full replacement query — one watch covers the set. PATCH replaces the entire query object and re-validates it (version, the type’s required filters, trigger_events), so resend every field, not just the one you’re changing:
    {
      "query": {
        "version": "v1",
        "filters": { "niceClasses": [9], "jurisdictions": ["US", "EU", "GB"] },
        "trigger_events": ["trademark.created"]
      }
    }