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

# Search Trademarks

> Search, filter, and browse trademarks across all supported offices

The canonical endpoint for discovering trademarks. Pass a text query to search by brand name with relevance ranking, or use filters to browse by office, status, class, date, and more. Every request must include at least one filter or a text query (`q`).

## Query Parameters

<ParamField query="q" type="string">
  Search query text (1-500 characters). When provided, results are ranked by relevance using multi-strategy matching (exact + fuzzy by default). Optional — omit for filter-only browsing.
</ParamField>

<ParamField query="strategies" type="string" default="exact,fuzzy">
  Search strategies to apply when `q` is provided, comma-separated. Any combination of `exact`, `fuzzy`, `phonetic`, `prefix`. Defaults to `exact,fuzzy` for fast results. Use `exact,phonetic,fuzzy,prefix` for comprehensive trademark clearance searches.
</ParamField>

<ParamField query="limit" type="integer" default="20">
  Results per page (1-100).
</ParamField>

<ParamField query="cursor" type="string">
  Opaque pagination cursor from a previous response.
</ParamField>

<ParamField query="include_total" type="boolean" default="false">
  When `true`, includes an accurate total count in `pagination.total_count`.
</ParamField>

<ParamField query="highlights" type="boolean" default="false">
  When `true`, includes highlight snippets for `mark_text` and `owner_names` fields.
</ParamField>

### Filters

All filter parameters are accepted at the top level of the query string. Arrays use comma-separated values. Date ranges support `_gte`, `_gt`, `_lte`, and `_lt` suffixes.

<ParamField query="offices" type="string">Office codes, comma-separated (e.g. `?offices=uspto,euipo`).</ParamField>
<ParamField query="jurisdictions" type="string">ISO jurisdiction codes, comma-separated (e.g. `?jurisdictions=US,EU`).</ParamField>
<ParamField query="nice_classes" type="string">Nice classification numbers 1-45, comma-separated (e.g. `?nice_classes=9,42`).</ParamField>
<ParamField query="status_primary" type="string">Primary status: `active`, `pending`, `inactive`, `unknown`. Comma-separated for multiple.</ParamField>
<ParamField query="status_stage" type="string">Status stage, comma-separated (e.g. `registered`, `published`, `examining`).</ParamField>
<ParamField query="mark_feature_type" type="string">Mark type: `word`, `figurative`, `combined`, `three_dimensional`.</ParamField>
<ParamField query="filing_route" type="string">Filing route: `direct_national`, `madrid_designation`, `direct_regional`.</ParamField>
<ParamField query="owner_id" type="string">Owner ID (`own_...`). Marks for that single per-office owner record.</ParamField>
<ParamField query="owner_name" type="string">Owner name substring match.</ParamField>

<ParamField query="entity_id" type="string">
  Resolved entity ID (`ent_...`). Returns marks across **all member owners** of the entity (every office) — the global-portfolio filter. Accepts a derived `ent_<owner-uuid>`. An entity resolving to more than 10,000 member owners returns `422 entity_too_large` with `error.reason: member_owners_too_large` (`member_count` / `member_count_limit`). See [Entities](/api-reference/parties/list-entities).
</ParamField>

<ParamField query="entity_group" type="string">
  Entity GROUP ID (`ent_...`). Returns marks across the whole GLEIF corporate family (root + all descendants) — "all Pfizer-group marks". Group-level, never identity. Two `422 entity_too_large` reasons apply: `family_graph_too_large` when the GLEIF family-graph walk exceeds its node/depth bound before owners are counted (carries `related_entity_limit` / `depth_limit`), or `member_owners_too_large` when the resolved member union exceeds the cap (carries `member_count` / `member_count_limit`).
</ParamField>

<ParamField query="owner_publicly_traded" type="boolean">`true` to return marks whose owner has a confirmed active SEC ticker match. `false` means no confirmed public-company match, not confirmed private.</ParamField>
<ParamField query="owner_has_lei" type="boolean">`true` to return marks whose owner has a confirmed GLEIF LEI match. `false` means no confirmed LEI match.</ParamField>
<ParamField query="owner_ticker" type="string">Exact owner ticker match, uppercased server-side (e.g. `AAPL`).</ParamField>
<ParamField query="owner_lei" type="string">Exact owner LEI match, uppercased server-side.</ParamField>
<ParamField query="attorney_id" type="string">Attorney ID (`att_...`).</ParamField>
<ParamField query="firm_id" type="string">Firm ID (`firm_...`).</ParamField>
<ParamField query="filing_date_gte" type="string">Filing date lower bound (YYYY-MM-DD).</ParamField>
<ParamField query="filing_date_lt" type="string">Filing date upper bound (exclusive).</ParamField>
<ParamField query="registration_date_gte" type="string">Registration date lower bound.</ParamField>
<ParamField query="registration_date_lt" type="string">Registration date upper bound.</ParamField>
<ParamField query="expiry_date_gte" type="string">Expiry date lower bound.</ParamField>
<ParamField query="expiry_date_lt" type="string">Expiry date upper bound.</ParamField>
<ParamField query="has_media" type="boolean">`true` to require at least one image.</ParamField>
<ParamField query="is_madrid" type="boolean">`true` to restrict to Madrid Protocol filings.</ParamField>

<Expandable title="More filters">
  | Parameter              | Type    | Description                                                                                                                                |
  | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
  | `office`               | string  | Single office code shortcut                                                                                                                |
  | `vienna_codes`         | string  | Vienna figurative codes, comma-separated                                                                                                   |
  | `status_reason`        | string  | Status reason codes, comma-separated                                                                                                       |
  | `challenge_states`     | string  | Active challenge states, comma-separated                                                                                                   |
  | `mark_legal_category`  | string  | `standard`, `certification`, `collective`                                                                                                  |
  | `right_kind`           | string  | Right kind (e.g. `trademark`)                                                                                                              |
  | `scope_kind`           | string  | Territorial scope kind, comma-separated                                                                                                    |
  | `owner_country`        | string  | Two-letter owner country code                                                                                                              |
  | `goods_services_text`  | string  | Free-text search in G\&S descriptions                                                                                                      |
  | `application_number`   | string  | Exact application number (requires `office`)                                                                                               |
  | `registration_number`  | string  | Exact registration number (requires `office`)                                                                                              |
  | `ir_number`            | string  | Madrid International Registration number                                                                                                   |
  | `origin_office_code`   | string  | Origin office code for Madrid filings                                                                                                      |
  | `renewal_due_date_gte` | string  | Renewal due date lower bound                                                                                                               |
  | `renewal_due_date_lt`  | string  | Renewal due date upper bound                                                                                                               |
  | `publication_date_gte` | string  | Publication date lower bound                                                                                                               |
  | `publication_date_lt`  | string  | Publication date upper bound                                                                                                               |
  | `termination_date_gte` | string  | Termination date lower bound                                                                                                               |
  | `termination_date_lt`  | string  | Termination date upper bound                                                                                                               |
  | `updated_at_gte`       | string  | Record updated-at lower bound. Accepts `YYYY-MM-DD` (coerced to start of day UTC) or full ISO 8601 datetime (e.g. `2024-01-15T00:00:00Z`). |
  | `updated_at_lt`        | string  | Record updated-at upper bound. Accepts `YYYY-MM-DD` or full ISO 8601 datetime.                                                             |
  | `has_proceedings`      | boolean | `true` to require at least one proceeding                                                                                                  |
  | `is_retracted`         | boolean | `true` to restrict to retracted marks                                                                                                      |
  | `is_series_mark`       | boolean | `true` to restrict to series marks                                                                                                         |
  | `renewal_due_before`   | string  | Alias for `renewal_due_date_lt`                                                                                                            |
</Expandable>

## Examples

<CodeGroup>
  ```bash cURL — search by name theme={null}
  curl -G "https://api.signa.so/v1/trademarks" \
    -H "Authorization: Bearer $SIGNA_API_KEY" \
    --data-urlencode "q=nike" \
    --data-urlencode "offices=uspto"
  ```

  ```bash cURL — filter by office and class theme={null}
  curl -G "https://api.signa.so/v1/trademarks" \
    -H "Authorization: Bearer $SIGNA_API_KEY" \
    --data-urlencode "offices=euipo" \
    --data-urlencode "nice_classes=9,42" \
    --data-urlencode "status_stage=registered"
  ```

  ```bash cURL — clearance search (all strategies) theme={null}
  curl -G "https://api.signa.so/v1/trademarks" \
    -H "Authorization: Bearer $SIGNA_API_KEY" \
    --data-urlencode "q=nova" \
    --data-urlencode "strategies=exact,phonetic,fuzzy,prefix" \
    --data-urlencode "offices=uspto,euipo" \
    --data-urlencode "nice_classes=9"
  ```

  ```bash cURL — public-company owner filter theme={null}
  curl -G "https://api.signa.so/v1/trademarks" \
    -H "Authorization: Bearer $SIGNA_API_KEY" \
    --data-urlencode "owner_publicly_traded=true" \
    --data-urlencode "owner_ticker=AAPL" \
    --data-urlencode "status_stage=registered"
  ```

  ```python Python theme={null}
  import requests

  resp = requests.get(
      "https://api.signa.so/v1/trademarks",
      headers={"Authorization": f"Bearer {SIGNA_API_KEY}"},
      params={
          "q": "nike",
          "offices": "uspto",
          "nice_classes": "25",
          "limit": 10,
      },
  )

  data = resp.json()
  for mark in data["data"]:
      print(f"{mark['mark_text']} — {mark['status']['stage']}")
  ```

  ```typescript TypeScript (SDK) theme={null}
  import { Signa } from "@signa-so/sdk";

  const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });

  const results = await signa.trademarks.list({
    q: "nike",
    offices: ["uspto"],
    nice_classes: [25],
    limit: 10,
  });

  for (const mark of results.data) {
    console.log(`${mark.mark_text} — ${mark.status.stage}`);
  }
  ```
</CodeGroup>

## Response

<ResponseExample>
  ```json Response theme={null}
  {
    "object": "list",
    "data": [
      {
        "id": "tm_abc123",
        "object": "trademark",
        "mark_text": "NIKE",
        "relevance_score": 95,
        "match_explanation": {
          "strategies_matched": ["exact"],
          "boost_factors": [
            { "factor": "status_active", "weight": 1.2 }
          ]
        },
        "primary_image_url": null,
        "status": { "primary": "active", "stage": "registered" },
        "office_code": "uspto",
        "jurisdiction_code": "US",
        "filing_date": "1971-02-04",
        "registration_date": "1974-04-16",
        "classifications": [
          { "nice_class": 25, "goods_services_text": "Clothing, footwear, headgear" }
        ],
        "owner_name": "Nike, Inc.",
        "owners": [
          {
            "id": "own_def456",
            "name": "Nike, Inc.",
            "country_code": "US",
            "companies": [
              {
                "source": "sec",
                "ticker": "NKE",
                "exchange": "NYSE",
                "lei": null,
                "entity_status": "active"
              }
            ]
          }
        ]
      }
    ],
    "has_more": true,
    "pagination": {
      "cursor": "eyJpZCI6ImFiYyJ9",
      "total_count": 142,
      "total_count_approximate": false
    },
    "search_meta": {
      "search_id": "srch_abc123",
      "query": "nike",
      "strategies_used": ["exact", "fuzzy"],
      "total_results": 142,
      "total_count_exact": true,
      "total_count_approximate": false,
      "execution_time_ms": 15
    },
    "aggregations": {},
    "request_id": "req_xyz789"
  }
  ```
</ResponseExample>

<ResponseField name="data" type="object[]">Trademark summary records — the slimmer list shape with the fields most useful for result cards. See [Get Trademark](/api-reference/trademarks/get-trademark) for the full record shape returned by single-record lookups.</ResponseField>
<ResponseField name="has_more" type="boolean">Whether more results are available.</ResponseField>
<ResponseField name="pagination.cursor" type="string">Pass this as `?cursor=` to get the next page.</ResponseField>
<ResponseField name="pagination.total_count" type="integer">Total matches. Only present when `include_total=true`. **Canonical location** — read this field across every list endpoint.</ResponseField>
<ResponseField name="pagination.total_count_approximate" type="boolean">Emitted alongside `total_count`. `false` when the count is exact; `true` when the search index capped the count at 10,000 for a deep search.</ResponseField>

<ResponseField name="search_meta" type="object">
  Query metadata: `search_id`, `query`, `strategies_used`, `execution_time_ms`.

  <Expandable title="search_meta fields">
    <ResponseField name="search_meta.search_id" type="string">Unique search identifier.</ResponseField>
    <ResponseField name="search_meta.query" type="string | null">The query text used.</ResponseField>
    <ResponseField name="search_meta.strategies_used" type="string[]">Search strategies that were applied.</ResponseField>
    <ResponseField name="search_meta.total_results" type="integer" deprecated>**Deprecated — use `pagination.total_count` instead. Will be removed in v1.1.** Total matching results (same as `pagination.total_count` when `include_total` is true).</ResponseField>
    <ResponseField name="search_meta.total_count_exact" type="boolean" deprecated>**Deprecated — use `pagination.total_count_approximate` (inverse of this flag) instead. Will be removed in v1.1.** Whether the total count is exact.</ResponseField>
    <ResponseField name="search_meta.total_count_approximate" type="boolean" deprecated>**Deprecated — use `pagination.total_count_approximate` instead. Will be removed in v1.1.** Whether the total count is approximate.</ResponseField>
    <ResponseField name="search_meta.execution_time_ms" type="integer">Query execution time in milliseconds.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="aggregations" type="object">Empty object `{}` on GET requests. Populated with faceted counts on POST when `options.aggregations` is provided.</ResponseField>
<ResponseField name="relevance_score" type="number | null">Normalized relevance score. Present when `q` is provided, `null` for filter-only queries or when `sort` is specified.</ResponseField>

<ResponseField name="match_explanation" type="object | undefined">
  Explains relevance scoring. Omitted when `sort` is specified.

  <Expandable title="match_explanation fields">
    <ResponseField name="match_explanation.strategies_matched" type="string[]">Array of strategy names that matched (e.g. `["exact", "fuzzy"]`).</ResponseField>
    <ResponseField name="match_explanation.boost_factors" type="object[]">Array of `{factor, weight}` objects describing score adjustments.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="primary_image_url" type="string | null">URL to the primary trademark image. Format: `https://api.signa.so/v1/trademarks/{id}/media/{media_id}`. Only present when `has_media` is true, `null` otherwise.</ResponseField>

<ResponseField name="owners" type="object[]">
  Summary-tier owner projections for search-backed rows. Omitted on some DB-backed summary rows.

  <Expandable title="Owner summary fields">
    <ResponseField name="owners[].id" type="string">Owner ID (`own_*`).</ResponseField>
    <ResponseField name="owners[].name" type="string">Owner display name.</ResponseField>
    <ResponseField name="owners[].country_code" type="string | null">Owner country code when available.</ResponseField>
    <ResponseField name="owners[].companies" type="object[]">Public company records linked to this owner. Omitted when there are no matched companies.</ResponseField>
    <ResponseField name="owners[].companies[].source" type="string">`sec` or `gleif`.</ResponseField>
    <ResponseField name="owners[].companies[].ticker" type="string | null">Ticker symbol for SEC matches.</ResponseField>
    <ResponseField name="owners[].companies[].exchange" type="string | null">Exchange for SEC matches.</ResponseField>
    <ResponseField name="owners[].companies[].lei" type="string | null">Legal Entity Identifier for GLEIF matches.</ResponseField>
    <ResponseField name="owners[].companies[].entity_status" type="string">`active`, `inactive`, or `delisted`.</ResponseField>
  </Expandable>
</ResponseField>

## Sort

By default, results are ranked by **relevance** when `q` is provided. For filter-only queries (no `q`), results are returned in index order (fast, unordered).

To explicitly sort results, use the `sort` parameter:

```
?sort=-filing_date          # newest filings first
?sort=expiry_date           # earliest expiry first
?sort=-filing_date,office_code  # multi-field (max 3)
```

Available sort fields: `filing_date`, `registration_date`, `expiry_date`, `renewal_due_date`, `updated_at`, `publication_date`, `termination_date`, `office_code`, `jurisdiction_code`.

<Note>
  When `sort` is specified alongside `q`, relevance scoring is bypassed — results are ordered purely by the sort field(s) and `relevance_score` will be `null`.
</Note>

## Errors

| Status | Type               | When                                                                |
| ------ | ------------------ | ------------------------------------------------------------------- |
| 400    | `validation_error` | No filter or query supplied, invalid date range, unknown sort field |
| 401    | `unauthorized`     | Missing or invalid API key                                          |
| 429    | `rate_limited`     | Rate limit exceeded ([details](/api-reference/rate-limits))         |

***

## Advanced: POST with JSON body

For complex queries with aggregations or long filter lists, use `POST /v1/trademarks` with a JSON body. This accepts the same filters and returns the same response shape.

<Note>
  `POST /v1/trademarks` is idempotency-**exempt** (it is a read-shaped
  search): the `Idempotency-Key` header is not required, and if you send one
  it is not enforced or replayed — the value's format is still validated.
  `GET` does not take one.
</Note>

### POST-only features

* `options.aggregations` — an **array of field names** to aggregate. Returns faceted counts for building filter UIs. Valid values: `status_stage`, `office_code`, `jurisdiction_code`, `nice_classes`, `filing_year`, `mark_feature_type`, `mark_legal_category`, `filing_route`, `right_kind`, `scope_kind`.
* `options.aggregations_only` — return only counts, skip result documents

### POST example

```bash cURL theme={null}
curl -X POST "https://api.signa.so/v1/trademarks" \
  -H "Authorization: Bearer $SIGNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "nova",
    "strategies": ["exact", "phonetic", "fuzzy", "prefix"],
    "filters": {
      "offices": ["uspto", "euipo"],
      "nice_classes": [9, 42],
      "status_stage": ["registered"],
      "filing_date": { "gte": "2020-01-01" }
    },
    "options": {
      "aggregations": ["office_code", "nice_classes", "status_stage"]
    },
    "limit": 20
  }'
```

<Expandable title="Full POST body reference">
  | Field                       | Type      | Description                                                                                                                                                                                |
  | --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
  | `query`                     | string    | Search query text (1-500 chars). Optional.                                                                                                                                                 |
  | `sort`                      | string    | Sort field(s), same as GET `sort` parameter.                                                                                                                                               |
  | `strategies`                | string\[] | Search strategies. Default: `["exact", "fuzzy"]`.                                                                                                                                          |
  | `filters`                   | object    | Same filters as GET, nested in an object. Arrays use JSON arrays, dates use `{"gte": "...", "lt": "..."}`.                                                                                 |
  | `options.aggregations`      | string\[] | Faceted counts: `status_stage`, `office_code`, `jurisdiction_code`, `nice_classes`, `filing_year`, `mark_feature_type`, `mark_legal_category`, `filing_route`, `right_kind`, `scope_kind`. |
  | `options.aggregations_only` | boolean   | Return only counts, no documents. Default: `false`.                                                                                                                                        |
  | `options.include_total`     | boolean   | Include accurate total count. Default: `false`.                                                                                                                                            |
  | `options.highlights`        | boolean   | Include highlight snippets. Default: `false`.                                                                                                                                              |
  | `limit`                     | integer   | Results per page (0-100). Default: `20`.                                                                                                                                                   |
  | `cursor`                    | string    | Pagination cursor from previous response.                                                                                                                                                  |
</Expandable>

## Related

* [Suggest Trademarks](/api-reference/trademarks/trademark-suggest) — typeahead autocomplete
* [Get Trademark](/api-reference/trademarks/get-trademark) — full detail for a single mark
* [Batch Get Trademarks](/api-reference/trademarks/batch-trademarks) — hydrate known IDs
