Automate Trademark Search with 10 Lines of Code

Search 147M+ trademarks across 200+ offices with one API call. Working trademark search API examples in curl and TypeScript, plus three patterns to ship.
7 min read

Most free trademark search tools give you a text box and a single office. You type a name, click search, wait, copy results into a spreadsheet, then do it again for the next office. Multiply by six jurisdictions and you've lost an afternoon. Trademark search automation fixes this.

Signa's trademark search API covers 147M+ records across 200+ offices. One request, four matching strategies, results in under 300ms. Here's what that looks like in ten lines of code.

Search for "AURORA" across every connected office with phonetic and fuzzy matching:

curl https://api.signa.so/v1/trademarks/search \
  -H "Authorization: Bearer sig_live_..." \
  -d '{
    "mark": {
      "text": "AURORA",
      "strategies": ["exact", "phonetic", "fuzzy"]
    }
  }'

The TypeScript SDK equivalent:

import Signa from '@signa/sdk';

const signa = new Signa({ apiKey: 'sig_live_...' });
const results = await signa.trademarks.search({
  mark: { text: 'AURORA', strategies: ['exact', 'phonetic', 'fuzzy'] }
});

console.log(`Found ${results.total} marks`);
for (const tm of results.data) {
  console.log(`${tm.mark_text} [${tm.office}] — ${tm.status}`);
  console.log(`  Classes: ${tm.nice_classes.join(', ')}`);
}

Ten lines. That single request fans out across six offices (USPTO, EUIPO, WIPO, CIPO, IPOS, IP Australia), runs three matching strategies in parallel, deduplicates overlapping hits, and returns a unified response.

Here's what a single result looks like in that response:

{
  "id": "tm_8v3kLmNp2x",
  "mark_text": "AURORA",
  "office": "USPTO",
  "status": "registered",
  "nice_classes": [9, 42],
  "owner": {
    "id": "own_4rTjWn9sQz",
    "name": "Aurora Technologies Inc."
  },
  "filing_date": "2021-03-15",
  "registration_date": "2022-01-08",
  "similarity_score": 1.0
}

Every result comes back with the same normalized structure regardless of which office it came from. The similarity_score tells you how closely the result matched your query (1.0 for exact, lower for fuzzy and phonetic hits). The status field is normalized across offices, so you get "registered" instead of USPTO's internal status code 700.

That one request replaces manual searches across six separate office websites. And it finishes in under 300ms.

How the trademark search API works under the hood

The strategies array controls how Signa matches your query against 147M+ records. Four strategies are available, and you can combine any of them in a single call.

Exact finds marks that match your query character-for-character. Search "AURORA" and you get "AURORA," not "AURORAA" or "AWRORA."

Phonetic uses Double Metaphone encoding to catch marks that sound like your query, even if they're spelled differently. Search "AURORA" and you'll also find "AWRORA," "ARORA," and similar variations. This is critical for pre-filing clearance searches because the legal standard for confusion is based on how marks sound, look, and feel to consumers, not just exact spelling.

Fuzzy uses edit-distance matching to find marks within a set number of character changes from your query. "AUROA," "AURRORA," and "AUROR" would all surface.

Prefix matches marks that start with your query. Search "AUR" and you'll get "AURORA," "AURELIUS," "AURUM," and everything else beginning with those three characters.

Combine all four in one request:

curl https://api.signa.so/v1/trademarks/search \
  -H "Authorization: Bearer sig_live_..." \
  -d '{
    "mark": {
      "text": "AURORA",
      "strategies": ["exact", "phonetic", "fuzzy", "prefix"]
    }
  }'

Results are deduplicated across strategies. If "AURORA" matches on both exact and phonetic, it appears once in the response.

The response also includes aggregations: bucketed counts of your results by office, status, and Nice class. Nice classes are the international system for categorizing goods and services into 45 classes (Class 9 covers software, Class 25 covers clothing). For a deeper breakdown, see the developer's guide to Nice classification.

{
  "aggregations": {
    "by_office": { "USPTO": 312, "EUIPO": 87, "WIPO": 45, "CIPO": 23, "IPOS": 8, "IPAU": 14 },
    "by_status": { "registered": 294, "pending": 112, "abandoned": 83 },
    "by_nice_class": { "9": 142, "42": 98, "35": 67, "25": 41 }
  }
}

Those aggregation numbers tell you something immediately: 312 results at the USPTO alone (which holds roughly 10M trademark records), heavy concentration in Class 9 (software) and Class 42 (technology services). If you're launching a software product called "Aurora," that's a crowded field.

Filtering and refining trademark search results

Raw search results across all offices and classes can be noisy. Filters let you narrow to exactly what you need.

Filter by office, Nice class, and status in a single request:

curl https://api.signa.so/v1/trademarks/search \
  -H "Authorization: Bearer sig_live_..." \
  -d '{
    "mark": {
      "text": "AURORA",
      "strategies": ["exact", "phonetic"]
    },
    "filters": {
      "office": ["USPTO", "EUIPO"],
      "nice_classes": [9, 42],
      "status": ["registered", "pending"]
    }
  }'

This scopes results to live and pending marks in software-related classes at the two largest offices. For a pre-filing clearance search, this is often the right starting point: you care about marks that could actually block your application, not abandoned filings from 2003.

Status values are normalized across offices. Signa maps the 167 USPTO status codes, EUIPO's status taxonomy, and every other office's system into a consistent set: registered, pending, abandoned, expired, opposed, cancelled. You don't need to learn six different status systems.

For large result sets, the SDK handles cursor-based pagination automatically with async iteration:

const search = signa.trademarks.search({
  mark: { text: 'AURORA', strategies: ['exact', 'phonetic'] },
  filters: { office: ['USPTO'], nice_classes: [9] }
});

for await (const trademark of search) {
  console.log(`${trademark.mark_text} — ${trademark.owner.name} — ${trademark.status}`);
}

The SDK fetches pages behind the scenes as you iterate. No manual cursor tracking, no while (has_more) loops. Each page request uses cursor-based pagination, which stays stable even if new trademarks are indexed mid-iteration.

Three patterns you can ship today

The search endpoint is a building block. Here are three patterns that turn it into product features.

Pattern 1: Pre-filing clearance check

Before filing a trademark application, run a phonetic and fuzzy search to surface potential conflicts:

const conflicts = await signa.trademarks.search({
  mark: { text: 'NIMBUS', strategies: ['phonetic', 'fuzzy'] },
  filters: { nice_classes: [9, 42], status: ['registered', 'pending'] }
});

console.log(`Found ${conflicts.total} potential conflicts in Classes 9 and 42`);

This catches sound-alikes and close spellings that an exact search would miss. A match here doesn't necessarily mean your application will be refused, but it's a signal worth investigating. Consult a trademark attorney for legal guidance specific to your situation.

For a complete walkthrough of building this into a user-facing tool, see how to build a brand name availability checker with Signa's API.

Pattern 2: Brand name availability endpoint

Wrap Signa's search in an Express handler to add trademark checking to your SaaS product:

app.get('/api/check-name', async (req, res) => {
  const { name, classes } = req.query;
  const results = await signa.trademarks.search({
    mark: { text: name, strategies: ['exact', 'phonetic'] },
    filters: { nice_classes: classes?.split(',').map(Number), status: ['registered', 'pending'] }
  });
  res.json({ available: results.total === 0, conflicts: results.total, results: results.data.slice(0, 5) });
});

This gives your users instant trademark feedback during name selection, domain registration, or product creation flows.

Pattern 3: Bulk listing screening

For e-commerce platforms or marketplaces that need to screen product listings against registered trademarks:

for (const listing of listings) {
  const hits = await signa.trademarks.search({
    mark: { text: listing.brand_name, strategies: ['exact'] },
    filters: { status: ['registered'] }
  });
  if (hits.total > 0) flagForReview(listing, hits.data);
}

For bulk workloads, be mindful of rate limits and batch requests with appropriate delays. The SDK handles retries automatically on rate limit responses.

Getting started

Install the trademark search SDK:

npm install @signa/sdk

Initialize with your API key:

import Signa from '@signa/sdk';

const signa = new Signa({ apiKey: 'sig_live_...' });

Signa uses prefixed API keys: sig_live_ for production, sig_test_ for sandbox. The sandbox environment returns real data structures with test data, so you can build and test your integration without touching production.

The SDK handles pagination, automatic retries with exponential backoff, and typed errors out of the box. If a request fails with a retryable error, the SDK retries it. If it fails with a validation error, you get a typed exception you can catch and handle.

For a complete integration walkthrough, the brand name availability checker guide walks through building a working app from zero to deployed.

For a full overview of the API's capabilities, see Introducing the Signa API. Sign up for free API access at signa.so.