Search every contiguous phrase, remove punctuation from comparison text, and return cleaned matches longest-first.
Run a query above to see raw JSON or parsed trademark cards.
Local Database Portal & API Playground
Search every contiguous phrase, remove punctuation from comparison text, and return cleaned matches longest-first.
Run a query above to see raw JSON or parsed trademark cards.
The USPTO Trademark Search API provides a localized, self-hosted search engine indexing millions of historical and daily active trademark filings. Rather than querying the USPTO Open Data Portal directly on every transaction (which is subject to connection limitations and rate throttling), this server aggregates data locally in a PostgreSQL instance optimized for heavy read loads.
It supports both fuzzy trigram searches (for matching spelling mistakes) and standard English full-text indexing, mapping trademark owner coordinates, status revisions, and international trademark classes.
The architecture isolates the heavy ingestion loops (the synchronization cron jobs) from the core API routes to prevent query performance degradation during bulk data loads.
sax stream processor. Rather than loading massive
USPTO files (often exceeding 1.5GB) into RAM, XML contents are parsed sequentially as a text stream,
buffering rows in batches of 500. This guarantees a stable memory ceiling of less than 200MB during
parser operations.
The database structures are optimized to facilitate immediate queries. Indices deploy customized features to accelerate specific route paths.
| Index Name | Type | Target Column | Purpose |
|---|---|---|---|
idx_tm_word_mark_trgm |
GIN (Trigram) | word_mark |
Fuzzy spelling similarity search (% operator) |
idx_tm_word_mark_normalized_trgm |
GIN (Expression Trigram) | word_mark |
Punctuation-insensitive fuzzy spelling similarity search |
idx_tm_word_mark_normalized |
B-Tree (Expression) | word_mark |
Fixed-length normalized fingerprint for punctuation-insensitive phrase matching |
idx_tm_word_mark_fts |
GIN (FTS) | word_mark |
Lexical keyword ranking (to_tsvector) |
idx_tm_owner_fts |
GIN (FTS) | owner_name |
Ranked corporate lookup |
idx_tm_goods_services_fts |
GIN (FTS) | goods_services |
Full-text search inside utility listings |
idx_tm_int_class |
GIN (B-Tree Alternative) | international_class |
Browsing marks in array blocks (e.g. ANY(int_class)) |
idx_tm_registration_date |
B-Tree (Descending) | registration_date |
Newest-registration date windows and ordering |
The schema deploys a PL/pgSQL function trigger update_updated_at() on the
trademarks table that updates the updated_at timestamp automatically whenever
any upsert triggers a modification.
Synchronization executes sequentially across two datasets:
npm run db:optimize-ingest to drop indices prior to the
ingestion run, and calling npm run db:restore-indexes to rebuild indices concurrently once
the batch finishes.
Both historical and daily sync loops run internal worker pools (concurrency = 2). This allows parallel retrieval and parsing of files while avoiding file conflicts and table locking deadlocks.
All core routes require authorization. Valid client requests must present a token via one of two channels:
Once a client token is authorized, the server returns standard rate limit headers indicating the token balance status:
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit |
Integer | Maximum allowed requests configured for this API Key. |
X-RateLimit-Remaining |
Integer | Remaining capacity in the current window. |
X-RateLimit-Reset |
Unix Timestamp | Time when the token limit window resets. |
This dictionary describes the purpose, type, and options of all settings available across the playground and the API routes.
The hostname of the USPTO API server. This defaults to the public domain
https://tm.merchdash.net (or http://localhost:3000 when running locally).
The client credential token. It gets matched against keys stored in the database's
api_keys table. Passing a valid key unlocks access and initiates customized rate limit
rules for the token. Generate a client key during setup and keep it out of source control.
The phrase search generates every contiguous word span, from the complete phrase down to individual
words. Matching ignores case, punctuation, symbols, and repeated whitespace. Semicolons, commas,
dots, and other special characters are removed from comparison text and returned trademark word
marks. Standalone one-character marks such as A or A! are excluded.
Comma-separated international classes. Short values are zero-padded, so
25 matches 025. Phrase search defaults to
009,018,020,021,024,025,035,040,041. Latest registrations defaults to all classes.
Use all to disable class filtering explicitly. The EUIPO and DPMA checks
(/euipo-check, /dpma-check) take plain, non-padded Nice numbers and
default to 25,24,35,40,31,21.
GET /v1/trademark/euipo-check/:phrase)Searches the European Union trademark registry (EUIPO) for a single phrase via the
Productor proxy service. Unlike phrase search, the phrase is sent exactly as provided
— there is no contiguous-span expansion. The adjustable classes query parameter accepts
plain Nice numbers (1–45) and defaults to 25,24,35,40,31,21.
The response returns the searched phrase, the registry (euipo),
the marketplace code EM, a count, and a records
array. Each record carries tm, filenumber, marketplace,
status, and tm_class. Any registry failure is reported in the
error field instead of throwing.
GET /v1/trademark/dpma-check/:phrase)Searches the German trademark registry (DPMA) for a single phrase via the Productor
proxy service. Behaves identically to the EUIPO check but queries DPMA: the registry is
dpma and the marketplace code is DE. The phrase is sent as-is,
and the adjustable classes parameter defaults to 25,24,35,40,31,21.
days selects an inclusive calendar-day window ending today and accepts values from
1 to 365 (default 30). minWords requires the
normalized trademark word mark to contain at least that many words and accepts values from
1 to 100 (default 1).
Optional boolean switches for including owner and attorney data in phrase-search results. Both
default to false.
The alphanumeric text string representing the name or phrase of the trademark you are trying to
query (e.g. nike, disney).
Configures the database query algorithm to locate trademark word marks. The differences and behaviors are as follows:
| Search Mode | Underlying Mechanism | Example Query | Matches Returned | Non-Matches / Excluded |
|---|---|---|---|---|
exact |
Performs a direct SQL equality test (=) on lowercase/uppercase string versions.
Fast, case-insensitive, but completely literal. |
nike |
NIKE, nike |
nike inc, nike shoes, red nike |
fulltext (Default) |
Uses PostgreSQL's native lexical analyzer to parse words, stem plurals/conjugations (e.g. "run" = "running"), and rank hits. Runs on English lexicons. | nike |
NIKE INC, NIKE ATHLETICS, NIKES |
nikee (no typo tolerance), nik |
fuzzy |
Calculates trigram similarity (overlapping 3-letter parts) using the pg_trgm
module. Catches typos, phonetics, and misspelled marks. |
starbux |
STARBUCKS, STARBUX COFFEE, STARBUCS |
star (too short/low similarity rating) |
Filters the query based on trademark registration status. Every result also includes a one-word
status.category.
all (Default): Returns all matches regardless of filing status (active, cancelled,
abandoned, pending, or expired).active: Restricts results to registered, maintained, and renewed trademarks.Categories: application, examination, approved,
published, opposition, appeal, registered,
suspended, abandoned, canceled, expired, and
unknown.
The 3-digit international classification identifier specifying the category of goods or services. Example classifications include:
025: Clothing, footwear, and headwear.009: Computers, software, and consumer electronics.035: Business advertising, retail administration, and office management.041: Entertainment services, publications, and educational courses.The unique 8-digit serial number assigned to a trademark application immediately upon filing at the USPTO. Consists strictly of numeric digits.
The unique registration number assigned to a trademark application once it completes examination and is officially registered by the USPTO.
Configures the size of the pagination batch. Accepts integers between 1 and
250. Default is 25.
Sets the page offset index. Default is 1.
Production deployment is completely automated by deploy.py. Run this from your deployment console:
The provisioning script automatically copies files, configures PostgreSQL databases, builds database schemas, installs PM2 daemon configurations, and sets up Nginx to act as a proxy forwarding traffic from port 80 to port 3000.