Skip to main content
Signa’s search supports full-text, phonetic, fuzzy, and prefix matching tuned specifically for trademark names.

Choosing GET or POST

The trademarks endpoint is exposed under both GET /v1/trademarks and POST /v1/trademarks. Both methods call the same service and return the same response shape. Pick whichever fits your call site. Everything (filters, strategies, pagination, highlights, include_total, sort, aggregations) works identically on both. On GET, aggregations is a comma-separated list and aggregations_only a boolean query parameter; on POST they live under options. For the full parameter reference, see Search Trademarks. The sections below show concrete usage patterns you can copy into your own code.

Search Strategies

By default, every search runs exact and fuzzy strategies simultaneously and merges the results. For comprehensive clearance searches, use all four: Only the strategies you pass run. strategies=exact returns whole-mark matches only; it never returns a longer mark that merely contains the query. Whole-mark matching folds lookalike characters (homoglyphs), so strategies=exact for timber also returns TIMB3R, labeled homoglyph; match=exact does not. match_explanation.strategies_matched reports finer labels (normalized, phrase, synonym, identifier, …), and each one belongs to a strategy listed in search_meta.strategies_used. strategies applies to the default match=similar mode only. The deterministic modes (match=exact, starts_with, ends_with, contains) take no strategies and return 400 validation_error if you send them. You can restrict which strategies are used by passing the strategies array (on POST) or a comma-separated strategies= parameter (on GET):
If you omit strategies, exact and fuzzy are used. For comprehensive trademark clearance searches, pass all four strategies explicitly: exact,phonetic,fuzzy,prefix.
There is no user-controllable fuzziness parameter. Fuzzy matching always uses AUTO internally, which adjusts edit distance based on the length of the query term.

Checking many exact spellings at once

When you already have the list of spellings to check (every one-letter variant of a word, a batch of candidate names), send them as q_any instead of one match=exact request per term. One request returns every mark that exactly equals any term, each hit tagged with matched_terms, and one page costs the same as any search page. See Several exact terms.
cURL (GET)

Filtering

Narrow results with filters. On POST, filters are nested under a filters object. On GET, they are flat query parameters using comma-separated values for arrays and flat underscore operators for date ranges.
Office codes are uppercase WIPO ST.3 two-letter codes: US (USPTO), EM (EUIPO), WO (WIPO), CA, SG, SE, CH, FR, AU, NO. Legacy lowercase codes (uspto, euipo, …) are accepted on requests permanently, and EU is accepted as an alias for EM. Responses always use the ST.3 form. Office display acronyms (e.g. IPA, IGE-IPI, INPI) are not an accepted input vocabulary — acronyms are not unique across offices; use ST.3 or legacy codes.
The two methods use different shapes. signa.trademarks.list() (GET) takes filters as flat top-level params, matching the query-string form. signa.trademarks.search() (POST) nests them under filters. Passing offices, nice_classes, status_stage, or other filter keys at the top level of a POST body returns a validation_error with unrecognized_keys. There is also no top-level search_type or type field: strategy selection happens through the strategies array.
Date filter operators: You can use both together for a range: "filing_date": { "gte": "2020-01-01", "lt": "2025-01-01" } (POST) or filing_date_gte=2020-01-01&filing_date_lt=2025-01-01 (GET).

Aggregations

Aggregations work on both methods: ?aggregations=office_code,status_stage on GET, or options.aggregations on POST. Bucket lists are top-N per field (for example 50 offices, 45 Nice classes, 250 owner countries); the document counts inside each bucket are not capped at 10,000 the way total_count is. An aggregation request is billed as one search page whether or not it returns documents. Available aggregation fields:
To get only the counts with no result documents, add "aggregations_only": true to options.

How filters apply to aggregations

By default every aggregation counts the same set as the results: q, the match mode, and every filter. For a single-valued field such as office_code or status_stage, the buckets add up to total_count (multi-valued fields such as nice_classes or owner_id can add up to more, because one mark lands in several buckets). aggregations_only=true follows the same rule. For a drill-down sidebar, set aggregation_mode=exclude_own_filter (options.aggregation_mode on POST). Each aggregation then applies every filter except its own: with offices=US&nice_classes=25, the office_code buckets ignore offices but still respect nice_classes, so the sidebar can show how many marks the other offices would add. The results and total_count still respect every filter.

Response Scoring

Search results include a relevance_score field, which is a normalized score from 0 to 100 (higher is more relevant). Results are sorted by relevance score in descending order by default. If you specify an explicit sort, relevance scoring is disabled and relevance_score is null.

Picking classes to filter on

If you do not know which Nice classes a query should be scoped to, send the description to POST /v1/classifications/suggest and feed the returned class_number values into nice_classes. It takes free text (“men’s running shoes, cushioned sole”) and returns ranked classes with a confidence and a rationale, so you can show the user why a class was picked. Ambiguous input comes back with ambiguous: true and a clarifying question instead of a guess.

Suggest

GET /v1/trademarks/suggest is an internal typeahead. It is not part of the published OpenAPI spec and its shape can change without notice. Use GET /v1/trademarks for search.
For autocomplete and typeahead on internal keys: