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

# Screen a Name

> Run a fast, deterministic knockout screen for one candidate name (beta)

<Warning>
  **Beta.** Requires the `screening:read` scope — granted to design partners
  during beta. This endpoint provides a risk signal, not legal advice.
</Warning>

## Overview

`GET /v1/screening` answers *"could this candidate name conflict with an
existing mark?"* Send a name and, optionally, its intended Nice classes or
goods/services. Screening searches live register coverage, assigns each
surfaced conflict a coarse band, and derives one request-level verdict.

The endpoint is synchronous, deterministic within its rules and corpus
versions, and text-only. It never returns a numeric similarity score. A
`clear` verdict means that no high- or medium-band conflict was found; it does
**not** mean that the mark is registrable.

Each request is billed at **10 units**.

## Request

```bash theme={null}
curl --get https://api.signa.so/v1/screening \
  --header "Authorization: Bearer $SIGNA_API_KEY" \
  --data-urlencode "q=KOFEE" \
  --data-urlencode "nice_classes=30,43" \
  --data-urlencode "jurisdictions=US,EU" \
  --data-urlencode "sensitivity=standard"
```

| Parameter        | Type                              | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `q`              | string                            | Candidate mark text; 2–200 non-whitespace characters. Exactly one of `q` or `trademark_id` is required.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `trademark_id`   | string                            | Existing register record (`tm_...`) to use as the candidate. Exactly one of `q` or `trademark_id` is required.                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `nice_classes`   | number\[]                         | Intended Nice classes, 1–45. Sent as a comma-separated list. Acts as a hard class filter.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `goods_services` | string                            | Free-text intended goods/services, up to 2,000 characters. Used for class inference when classes are omitted and for goods/services matching when supported by the active resolver.                                                                                                                                                                                                                                                                                                                                                                                         |
| `jurisdictions`  | string\[]                         | Territory codes such as `US` and `EU`. Default: all live-coverage jurisdictions. Screening always applies protection-scope expansion, and unlike [Search Trademarks](/api-reference/trademarks/list-trademarks) there is no `territory_match` opt-out: a request for a country pulls in EU-wide rights that protect there (a EUTM can block a French launch), and a request for a region (`EU`) pulls in **both** the regional register and every member state's national register (a French national mark can block an EU launch). Screening always errs toward inclusion. |
| `offices`        | string\[]                         | Registering office codes, uppercase ST.3, such as `US` and `EM`. Default: all live offices.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `include`        | `live` \| `all`                   | `live` by default; `all` also includes dead marks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `sensitivity`    | `strict` \| `standard` \| `broad` | Match-tier admission threshold. `strict` admits exact/normalized matches; `standard` adds close fuzzy and strong phonetic matches; `broad` adds weaker fuzzy matches.                                                                                                                                                                                                                                                                                                                                                                                                       |
| `limit`          | number                            | Page size from 1–50. Default: 20.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |

Array query parameters use comma-separated values, without brackets.

## Screen an existing mark

Use `trademark_id` instead of `q` for register-to-register discovery. Screening
uses the record's mark text and, when you omit both `nice_classes` and
`goods_services`, its own Nice classes as the intended-use profile. The
candidate's collapsed family is removed before conflicts are banded, so it
cannot appear as its own result.

```bash theme={null}
curl --get https://api.signa.so/v1/screening \
  --header "Authorization: Bearer $SIGNA_API_KEY" \
  --data-urlencode "trademark_id=tm_0190f2d5-8e4b-7c1a-a8d3-123456789abc"
```

The response echoes the source in `screening.candidate.trademark_id`. Unknown
records return `404 not_found`; records without textual mark content, such as
design-only marks, return `422 not_screenable`.

## Bands and verdicts

Every item in `data[]` is a `screening_hit` with one closed risk band:

| Band     | Meaning                                                                       |
| -------- | ----------------------------------------------------------------------------- |
| `high`   | Strongest combination of name match, goods/services overlap, and live status. |
| `medium` | A meaningful conflict signal that needs review.                               |
| `low`    | A surfaced but lower-priority signal, including admitted dead-mark results.   |

The leading `screening.verdict` summarizes the full banded result set, not only
the returned page:

| Verdict        | Rule                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `high_risk`    | At least one high-band conflict exists.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `caution`      | No high-band conflict exists, but at least one medium-band conflict exists.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `needs_review` | No high- or medium-band conflict was found, but the screen could not be completed to the standard required to say `clear`. The usual cause is incomplete register coverage for a requested territory; a stale office corpus, a capped analysis horizon, a failed analysis lane, an unsupported language, low-confidence class inference, or a coverage assessment that could not be read at all produce it too. When a coverage assessment is present, the [`coverage`](#coverage) block carries the details; it can be absent when the assessment itself failed. |
| `clear`        | No high- or medium-band conflict exists **and** every requested territory's register is covered live in Signa. Clear does not mean registrable.                                                                                                                                                                                                                                                                                                                                                                                                                   |

Found conflicts always band high or medium regardless of coverage: observed risk
is never suppressed. The coverage gate only ever downgrades a would-be `clear`,
it never upgrades a genuine conflict. Treat `needs_review` as "we could not rule
this out", not as a weaker `clear`.

Hits also explain the coarse classification through `reason_codes`,
`mark_match`, `goods_services_match`, `jurisdiction_match`, and a separate
`litigation_risk` block. Reason codes and warnings are extensible; clients
should tolerate values they do not yet recognize.

## Coverage

A clearance verdict for a territory is only as trustworthy as the registers
Signa can actually see there. If the national register that protects a requested
territory is not connected live (for example a request scoped to `DE` when the
German national register is dark), national-only marks in that territory are
invisible, so a zero-conflict screen must **not** read as `clear`. The
`screening.coverage` block reports exactly which registers gated the verdict.

```json theme={null}
"coverage": {
  "offices": [
    { "office": "US", "status": "complete", "as_of": "2026-07-20T00:00:00Z" },
    { "office": "EM", "status": "complete", "as_of": "2026-07-20T00:00:00Z" }
  ],
  "territories": [
    {
      "territory": "DE",
      "national_register": { "office": "DE", "covered": false },
      "regional_registers": [{ "code": "EU", "covered": true }],
      "complete": false
    }
  ],
  "complete_for_clear": false
}
```

This example is abridged to the coverage-gate axes. The served `coverage` object
also always includes `classes`, `lanes`, `language`, and `horizon`, the other
completeness inputs that can hold a verdict at `needs_review`.

* **`offices`** is the register-freshness axis. Each entry is a public office code
  in WIPO **ST.3** form (`US`, `EM` for the EUIPO), with a `status`
  (`complete` / `partial` / `stale` / `unavailable`) and an `as_of` corpus
  watermark. It lists the offices that gated this verdict: the requested offices
  when `offices` was supplied, the national plus regional and member registers
  when `jurisdictions` was supplied, or every live office when the request is
  unscoped.
* **`territories`** is the protection-scope axis, present when `jurisdictions`
  was supplied. Codes here are **jurisdiction** codes (`DE`, `EU`), not ST.3
  office codes. For each requested territory it reports its own
  `national_register`, the `regional_registers` that also protect there (a
  country belonging to `EU` shows an `EU` entry), and whether the whole set is
  `complete`.
* For a **regional** request (`jurisdictions=EU`) a territory entry adds
  `member_registers: { total, uncovered[] }`, summarizing how many member-state
  national registers are dark; `regional_registers` is still present but empty
  (the region is its own register). An EU screen
  stays `needs_review` while member registers are uncovered, and flips to `clear`
  only once they are live and fresh, the same principle as the `DE` example.
* **`complete_for_clear`** is the single boolean the verdict gate reads. When it
  is `false`, a would-be `clear` is downgraded to `needs_review` and
  `screening.note` names the dark register. `coverage` is present on every
  screened response. When the coverage assessment itself cannot be completed, the
  block fails closed with `complete_for_clear: false` and an empty `offices`,
  which signals that coverage could not be verified and forces the verdict to
  `needs_review`.

## Response

```json theme={null}
{
  "object": "list",
  "screening": {
    "verdict": "high_risk",
    "summary": { "high": 1, "medium": 0, "low": 0, "truncated": false },
    "litigation_risk": { "high": 0, "medium": 0 },
    "candidate": { "mark": "KOFEE", "normalized": "kofee" },
    "rules_version": "screening-v1",
    "as_of": "2026-07-13T00:00:00.000Z",
    "admitted_match_levels": ["exact", "normalized", "fuzzy_1", "phonetic_strong"],
    "coverage": {
      "offices": [{ "office": "US", "status": "complete", "as_of": "2026-07-20T00:00:00Z" }],
      "territories": [
        { "territory": "US", "national_register": { "office": "US", "covered": true }, "regional_registers": [], "complete": true }
      ],
      "complete_for_clear": true
    },
    "warnings": []
  },
  "data": [
    {
      "object": "screening_hit",
      "risk_level": "high",
      "reason_codes": ["exact_mark", "same_nice_class", "live_status"],
      "mark_match": { "level": "identical", "admitted_match_levels": ["exact"] },
      "goods_services_match": { "level": "same_class", "matched_nice_classes": [30] },
      "jurisdiction_match": { "requested": ["US", "EU"], "matched": ["US"] },
      "litigation_risk": {
        "level": "unknown",
        "owner_publicly_traded": null,
        "owner_ticker": null,
        "prior_proceedings": null,
        "owner_portfolio_size": null
      },
      "trademark": { "id": "tm_…", "object": "trademark", "mark_text": "KOFEE" }
    }
  ],
  "has_more": false,
  "pagination": { "cursor": null },
  "request_id": "req_…"
}
```

`screening.rules_version` and `screening.as_of` identify the rules and corpus
freshness behind the result. `screening.inferred_nice_classes` appears only
when class inference ran (i.e. `nice_classes` was omitted from the request).

## Warnings and limitations

* `warnings` is an open set. Handle known values and safely display or log new
  values rather than rejecting the response.
* A missing goods/services description may produce `no_goods_services`; the
  result then has less context for class and goods/services matching.
* `summary.truncated: true` means the analysis horizon was capped. It is
  separate from `has_more`, which describes response pagination.
* Screening v1 is text-only. It does not compare logos, designs, Vienna codes,
  or images.
* Backend failures return an error rather than a partial or false `clear`.
* Screening responses are served `Cache-Control: private, no-store`. A screening
  result reflects live register coverage at request time, so it is not safe to
  cache client-side, re-run the screen rather than replaying a stored response.

## SDK

```typescript theme={null}
const result = await signa.screening.screen({
  q: "KOFEE",
  nice_classes: [30, 43],
  jurisdictions: ["US", "EU"],
  sensitivity: "standard",
});

console.log(result.screening.verdict);
for (const hit of result.data) {
  console.log(hit.trademark.mark_text, hit.risk_level);
}
```
