Developer Reference

Trademark API Reference

Complete endpoint reference for the Goalie IP trademark API: request and response schemas for both endpoints, every search parameter, all response fields, status and drawing codes, error codes, and rate limits. New here? Start with the product overview →

Overview

This is the endpoint reference for the Goalie IP USPTO trademark API — structured access to a continuously-refreshed copy of the USPTO trademark dataset, the same data that powers our search tools. Query by mark name, owner, status, international class, serial number, and more.

Evaluating rather than integrating? The product overview covers features, pricing, and how this API compares to TSDR, and the USPTO TSDR API guide explains what TSDR itself does. Everything below assumes you already have a key.

Base URLhttps://www.goalieip.com
Versionv1
FormatJSON request and response bodies
AuthBearer token in Authorization header
Data sourceGoalie IP's own refreshed copy of the USPTO trademark dataset
UpdatedDaily, ingested from USPTO bulk data (occasionally a day behind)
Data source & freshness. This API serves Goalie IP's own copy of the USPTO trademark dataset, ingested from USPTO bulk data and refreshed daily (occasionally a day behind) — not a live connection to USPTO systems. Each record's updatedAt reflects its last refresh. Goalie IP is not affiliated with, or endorsed by, the USPTO.

Authentication

Every request must include your API key as a Bearer token in the Authorization header. Keys are created and managed in your portal.

Authorization: Bearer gip_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are prefixed with gip_live_ and are 41 characters total. The Bearer prefix is recommended but optional — a bare Authorization: gip_live_… is also accepted, because some directories and clients forward an API-key field verbatim without a scheme. Keep them secret — they are shown only once at creation. You can create up to 5 active keys per account.

Always call the www. host directly. Send requests to https://www.goalieip.com/…. The apex goalieip.com redirects to www, and many HTTP clients drop the Authorization header (returning 401) or downgrade POST→GET (returning 405) when following that redirect.

Quick start

Search for all active registrations of a mark in a specific class:

curl -X POST https://www.goalieip.com/api/v1/trademarks/search \
  -H "Authorization: Bearer gip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "markLiteral": "ACME",
    "markLiteralMode": "exact",
    "currentStatusCode": ["700", "800"],
    "internationalClasses": ["025"],
    "page": 1,
    "pageSize": 25
  }'

Look up a specific trademark by serial number:

curl https://www.goalieip.com/api/v1/trademarks/97123456 \
  -H "Authorization: Bearer gip_live_your_key_here"

MCP server (for AI agents)

The same trademark data is available over the Model Context Protocol, so an AI agent can search the US federal register directly — no HTTP client to write and no schema to teach it. See the trademark MCP server overview for how it compares to a TSDR lookup. It is included with every API plan at no extra cost and uses the same key and the same monthly quota as the REST endpoints.

Endpointhttps://www.goalieip.com/api/mcp
TransportStreamable HTTP
Protocol revisions2026-07-28 (native) and 2025-11-25 (supported)
AuthenticationBearer API key (same as the REST API), or OAuth 2.1 — one-click in Claude (Connectors Directory) and ChatGPT
Toolssearch_trademarks, get_trademark, find_similar_marks, get_deadlines, get_account

Install from Claude or ChatGPT (OAuth — one click)

Claude: open Goalie IP Trademark Search in the Claude Connectors Directory (or search for “Goalie” under Connectors) and click Connect. ChatGPT: open the Plugins Directory, search for Goalie, and click Install plugin. Either way you'll be sent to GoalieIP to sign in and approve access — no API key to copy and no config file to edit. The connector then searches on your behalf, with usage counting against your account's plan and quota. Revoke access anytime from your portal.

New here? Create a free account first, then click the link in the verification email — an unverified account is refused at the approval step. OAuth connections start on the free tier (200 calls/month) and inherit your plan's limits when you upgrade. For editors and scripts that take a static token, the API-key methods below are simpler.

Claude Code

claude mcp add --transport http goalieip \
  https://www.goalieip.com/api/mcp \
  --header "Authorization: Bearer gip_live_your_key_here"

Claude API MCP connector (for your own code — not the Claude Desktop app, which is below)

Use this only when your own program calls the Anthropic Messages API and you want Claude to reach our trademark tools while it answers. Anthropic makes the connection to our server for you — there is no config file to edit and nothing to install locally. The request needs three things together: the mcp-client-2025-11-20 beta header, an mcp_servers entry, and a matching mcp_toolset in tools (the API rejects the call if the toolset is missing).

import anthropic

client = anthropic.Anthropic()  # your ANTHROPIC_API_KEY

message = client.beta.messages.create(
    model="claude-opus-4-5",  # or any current Claude model
    max_tokens=1024,
    betas=["mcp-client-2025-11-20"],
    mcp_servers=[
        {
            "type": "url",
            "url": "https://www.goalieip.com/api/mcp",
            "name": "goalieip",
            "authorization_token": "gip_live_your_key_here",
        }
    ],
    tools=[{"type": "mcp_toolset", "mcp_server_name": "goalieip"}],
    messages=[
        {"role": "user", "content": "Find live trademarks for GOALIE in class 25."}
    ],
)

Two different keys are in play: your Anthropic API key authenticates the call to Anthropic, and your GoalieIP key (gip_live_…) goes in authorization_token so Anthropic can reach our server on your behalf. This is a request from code — not a snippet to paste into any desktop or client config file.

Any MCP client (generic config)

{
  "mcpServers": {
    "goalieip": {
      "type": "http",
      "url": "https://www.goalieip.com/api/mcp",
      "headers": {
        "Authorization": "Bearer gip_live_your_key_here"
      }
    }
  }
}

Claude Desktop

The simplest route is the directory: add Goalie IP Trademark Search and sign in, as above. Use the steps below only if you want to connect with an API key instead — Claude Desktop's Add connector screen has no field for one, so a key-based connection goes through a small local bridge (mcp-remote) that attaches your key for you. It runs automatically; you only edit one config file. Two steps trip most people up, so follow these in order.

1. Find the config file

The reliable way: in Claude Desktop open Settings → Developer → Edit Config. That opens the exact file (creating it if it doesn't exist). To locate it by hand instead:

Windows:  %APPDATA%\Claude\claude_desktop_config.json
macOS:    ~/Library/Application Support/Claude/claude_desktop_config.json

On Windows, paste that path into the File Explorer address bar. Turn on View → File name extensions first, so your editor can't silently save it as .json.txt — Claude only reads the exact .json.

2. Fully quit Claude Desktop before you edit — the step people miss

Closing the window is not enough. Claude Desktop keeps running in the background and rewrites this file with its own copy when it finally exits, erasing your edits. If your changes keep vanishing, this is why. Quit it completely first:

  • Windows: right-click the Claude icon in the system tray (bottom-right, possibly under the ^ arrow) → Quit. Then open Task Manager (Ctrl+Shift+Esc) and End task on any remaining Claude processes.
  • macOS: Claude menu → Quit (⌘Q). Confirm none remain in Activity Monitor.

3. Paste the configuration and save

Replace the file's contents with this, using a key from your portal:

{
  "mcpServers": {
    "goalieip": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote@latest",
        "https://www.goalieip.com/api/mcp",
        "--header", "Authorization: Bearer gip_live_your_key_here"
      ]
    }
  }
}

Works on macOS and Windows as written; the bridge needs Node.js installed. Prefer to keep your key out of the file? Put it in an env block and reference it: add "env": { "GOALIE_KEY": "gip_live_…" } and change the header value to Authorization: Bearer ${GOALIE_KEY}.

Windows fallback: if Claude Desktop reports the server failed to start, your setup may not spawn npx directly. Wrap it in cmd: set "command": "cmd" and make args begin "/c", "npx", "-y", "mcp-remote@latest", … — the rest is unchanged.

4. Reopen Claude Desktop

Start it again and give it a few seconds — the first launch downloads the bridge. goalieip then appears under Settings → Developer, and the tools are available in a new chat.

Troubleshooting connections

SymptomCause and fix
406 Not AcceptableYour client is sending an Accept header that excludes text/event-stream. Clients on protocol revision 2025-11-25 must accept both application/json and text/event-stream. Send Accept: application/json, text/event-stream. A missing header or */* is handled for you. Clients on 2026-07-28 are unaffected — that path ignores Accept entirely.
401 after a redirectYou configured the apex host. goalieip.com issues a 301 to www, and many clients drop the Authorization header when following it. Always configure https://www.goalieip.com/api/mcp.
400 on every callOn revision 2026-07-28, requests must carry the Mcp-Method header and self-describe via _meta. Most clients handle this; a hand-rolled one may not.
Responses look like event: messageThat is Server-Sent Events framing, which is correct for revision 2025-11-25 and expected by clients that speak it. The 2026-07-28 path always returns a plain JSON body instead, with no stream parsing required.
401 from a directory or hosted clientPaste only the key itself into an API-key field. Both Bearer gip_live_… and a bare gip_live_… are accepted, so no scheme prefix is needed. A 401 here means the key is wrong or revoked, not mis-formatted — check it in your portal.
Config edits keep vanishingClaude Desktop only: it rewrites claude_desktop_config.json from its own copy on exit, so edits made while it is running are lost. Fully quit it first — including the system-tray / menu-bar process — then edit. See Claude Desktop above.

The server answers both protocol revisions on the same URL and selects per request, so there is nothing to configure either way. Verified clients: Claude Code, the Claude API MCP connector, and Claude Desktop (via the bridge above). If your client cannot reach a remote Streamable HTTP server at all, that is a client limitation rather than a server setting — tell us which one and we will test it.

How results differ from the REST API

Tool results are read into a model's context window, so search_trademarks returns a compact summary of each match — serial number, mark, owner, status, filing and registration dates, classes, and the opening of the goods/services text — rather than the full record. Page size defaults to 10 and is capped at 15. Call get_trademark with a serial number for the complete record, including the full goods/services text, owner details, status history, and classifications. The REST API is unchanged and still returns full records at up to 500 per page. find_similar_marks screens a proposed name in one call — exact matches, spelling variants, and sound-alikes, ranked by match strength and by how closely their classes relate using the USPTO coordinated-class table, with dead marks listed separately (every strong match, more when the field is crowded, 100 per page with the first 10 in full detail; give classes for focused results). get_deadlines reports what is due and when — for one serial number, or for an owner's marks (soonest first, 15 per page with a page parameter for the rest) — covering office action responses, statement of use and extension deadlines, Section 8 and Section 71 declarations, Section 9 renewals, and grace periods; each date is computed from the record's status and dates and should be confirmed with the USPTO. A fifth tool, get_account, reports the connected account, plan tier, and calls used, included, and remaining this billing period; it takes no arguments and does not count against your quota.

Every search must include at least one narrowing filter — markLiteral, ownerName, serialNumber, registrationNumber, goodsAndServices, or one of the other text filters. Class, status, and date filters alone match too much of the register to run. When a query is rejected or times out, the tool returns a message naming the parameter to change, so an agent can correct itself and retry.

Treat record text as untrusted input. Fields such as the mark, owner name, and goods/services description are free text supplied by whoever filed the application, and every US application becomes a public record. An agent reading them is therefore consuming attacker-influenceable content, and a filing could contain text crafted to look like instructions. Our tool responses fence record data and label it as data, but if you build your own agent on this API, do not let record text drive tool calls or privileged actions without your own checks.

Each tool call counts as one API call against your monthly quota, and the same per-tier burst limits apply. Note that agents typically make several tool calls per question, so MCP usage consumes quota faster than a scripted integration. Coverage is US federal (USPTO) data only — see the FAQ.

Code examples

Common recipes in Python and Node.js. Each call returns JSON; replace gip_live_your_key_here with a key from your portal.

Exact mark query (Python)

import requests

resp = requests.post(
    "https://www.goalieip.com/api/v1/trademarks/search",
    headers={"Authorization": "Bearer gip_live_your_key_here"},
    json={
        "markLiteral": "ACME",
        "markLiteralMode": "exact",
        "currentStatusCode": ["700", "800"],  # live / registered
        "page": 1,
        "pageSize": 25,
    },
)
data = resp.json()
print(data["meta"]["total"], "matches")
for tm in data["data"]:
    print(tm["serialNumber"], tm["markLiteral"], tm["currentStatusCode"])

Serial-number status as JSON (Node.js)

const res = await fetch(
  "https://www.goalieip.com/api/v1/trademarks/97123456",
  { headers: { Authorization: "Bearer gip_live_your_key_here" } }
);
const { data } = await res.json();
console.log(data.markLiteral, "→", data.currentStatusCode, data.currentStatusDate);

Fuzzy mark-literal search (curl)

Find confusingly similar marks using trigram matching — useful for clearance and watch workflows.

curl -X POST https://www.goalieip.com/api/v1/trademarks/search \
  -H "Authorization: Bearer gip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "markLiteral": "Kodak", "markLiteralMode": "fuzzy", "pageSize": 50 }'

Search by owner and class (Python)

resp = requests.post(
    "https://www.goalieip.com/api/v1/trademarks/search",
    headers={"Authorization": "Bearer gip_live_your_key_here"},
    json={
        "ownerName": "Nike, Inc.",
        "internationalClasses": ["025", "035"],
        "filingDateFrom": "2020-01-01",
        "sortField": "filingDate",
        "sortDir": "desc",
    },
)
print(resp.json()["meta"]["total"], "marks")

Pseudo-mark search (curl)

The pseudo mark is the USPTO's normalized spelling of a stylized or intentionally misspelled mark — searching it finds phonetic equivalents that a literal search misses (e.g. "KWIK" filings via "QUICK").

curl -X POST https://www.goalieip.com/api/v1/trademarks/search \
  -H "Authorization: Bearer gip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "pseudoMark": "QUICK", "currentStatusCode": ["700", "800"] }'

Design search code lookup (curl)

Find marks by their figurative elements using USPTO design search codes (dots optional).

curl -X POST https://www.goalieip.com/api/v1/trademarks/search \
  -H "Authorization: Bearer gip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "designSearchCodes": ["05.03.10"], "internationalClasses": ["025"] }'

Full-text goods/services search (curl)

Use goodsAndServicesMode: "words" for whole-word full-text matching with stemming — far faster than contains for common terms, and supports OR and -exclusion. Results come back newest-first.

curl -X POST https://www.goalieip.com/api/v1/trademarks/search \
  -H "Authorization: Bearer gip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "goodsAndServices": "software -mobile", "goodsAndServicesMode": "words" }'

GET/api/v1/trademarks/{serialNumber}

Retrieve a single trademark record by its USPTO serial number. Returns the full record or 404 if not found.

GET /api/v1/trademarks/97123456
Authorization: Bearer gip_live_...

Response

{
  "data": {
    "serialNumber": "97123456",
    "registrationNumber": "6789012",
    "markLiteral": "NIKE",
    ...
  },
  "meta": {
    "callsUsed": 2,
    "callsRemaining": 4998
  }
}

Search parameters

At least one narrowing filter is required (see above); all other fields are optional. Combining multiple fields narrows results (AND logic).

Substring filters (any field described as "substring match") require at least 3 characters — shorter patterns cannot use the search indexes and are rejected with a 400. The one exception is markLiteral with markLiteralMode: "exact", which accepts short marks like "3M".

Substring filters ignore punctuation between words: a multi-word value also matches its words joined by a hyphen, period, slash, or nothing at all, so "COCA COLA" finds COCA-COLA and COCACOLA, and "COCA-COLA" finds COCA COLA. Exact mode, fuzzy mode, and goods/services words mode are unaffected.
Changed October 8, 2026: previously a substring filter matched only the punctuation you typed, so "COCA COLA" missed COCA-COLA. Request and response formats are unchanged. Results are the same as before or more: every record that matched before still matches, and multi-word searches can return more (an owner search for "COCA COLA" went from 12 records to about 2,300).

Mark filters

FieldTypeDescription
markLiteralstringThe text of the mark. Case-insensitive.
markLiteralMode"contains" "exact" "fuzzy"How to match markLiteral. contains — substring match (default). exact — full string equality. fuzzy — spelling similarity (trigram matching): marks scoring above 0.3 that contain a word spelled like one in your query, ordered most similar first. Catches typos and spelling variants; it does not find sound-alikes spelled differently (KWIK vs QUICK).
Changed October 6, 2026: fuzzy now looks for marks containing a similarly spelled word, which made short queries that used to time out (e.g. LILAH, CODAK) return in about a second. Request and response formats are unchanged. Results are the same as before or slightly fewer: a mark similar only as a whole string, with no similar word, can drop out (measured 0–4% of matches, all at the edge of the 0.3 cutoff).
markDrawingCodestringFilter by drawing type code. See Drawing codes.

Statement filters

FieldTypeDescription
pseudoMarkstringSubstring match on the pseudo mark — the USPTO's normalized spelling of a stylized or intentionally misspelled mark (e.g. "QUICK" for the mark "KWIK"). Useful for finding phonetic equivalents.
translationstringSubstring match on the English translation of foreign wording in the mark.
transliterationstringSubstring match on the transliteration of non-Latin characters in the mark.
disclaimerstringSubstring match on disclaimed wording (matter the owner claims no exclusive right to).
markDescriptionstringSubstring match on the description of the mark's design elements.

Owner & attorney filters

FieldTypeDescription
ownerNamestringSubstring match on the registrant/owner name.
attorneyNamestringSubstring match on the attorney of record.
attorneyDocketNumberstringSubstring match on the attorney's internal docket reference.
correspondentAddressstringSubstring match on the mailing address of the correspondent of record.
domesticRepresentativeNamestringSubstring match on the domestic representative (US contact for foreign applicants).

Classification & goods filters

FieldTypeDescription
internationalClassesstring[]Filter by Nice Classification codes. Pass multiple to match any (OR logic). Values are zero-padded three-digit strings, e.g. "025", "035". See the 45 trademark classes.
goodsAndServicesstringSearch the goods and services description. See goodsAndServicesMode for match behavior.
goodsAndServicesMode"contains" "words"How to match goodsAndServices. contains — substring match anywhere, including inside words (default). words — full-text whole-word match with English stemming ("shoes" matches shoe), supporting OR and -exclusion. Use words for a common single term (e.g. "software", "footwear"): it is far faster than contains, which times out on very common terms. Results default to newest-first. Multiple words are matched together (AND); a query combining only very common words can still time out (a 504) — prefer one distinctive term. Words mode matches whole words only, so "tooth" will not match toothbrush.
designSearchCodesstring[]Filter by USPTO design search codes for figurative elements. Pass multiple to match any (OR logic). Codes are 6 digits — category, division, section — with or without dots: "050310" and "05.03.10" are equivalent.

Status & identifier filters

FieldTypeDescription
serialNumberstringExact match on the USPTO serial number.
registrationNumberstringExact match on the registration number.
currentStatusCodestring[]Filter by one or more status codes (OR logic). E.g. ["700", "800"] for marks registered or renewed. Ranges like "700-799" are accepted, but code ranges mix live and dead statuses (710 is cancelled); use liveStatus for that. See Status codes.
liveStatus"live" | "dead"live — registered and pending marks only. dead — abandoned, cancelled, and expired marks only. Combines with currentStatusCode (both must match). Not a narrowing filter on its own.
Added October 8, 2026.
cancellationCodestringExact match on the cancellation code, for cancelled registrations.

Administrative filters

FieldTypeDescription
employeeNamestringSubstring match on the USPTO examining attorney assigned to the application.
currentLocationstringSubstring match on the file's current physical location at the USPTO (e.g. "PUBLICATION AND ISSUE SECTION").
lawOfficeAssignedLocationCodestringExact match on the assigned USPTO law office code (e.g. "L70").

Date range filters

FieldTypeDescription
filingDateFromISO 8601 date stringInclude only records filed on or after this date. Example: "2023-01-01".
filingDateToISO 8601 date stringInclude only records filed on or before this date. Example: "2023-01-01".
currentStatusDateFromISO 8601 date stringFilter by status change date (on or after). Example: "2023-01-01".
currentStatusDateToISO 8601 date stringFilter by status change date (on or before). Example: "2023-01-01".
firstUseDateFromISO 8601 date stringFilter by claimed date of first use anywhere (on or after). Example: "2023-01-01".
firstUseDateToISO 8601 date stringFilter by claimed date of first use anywhere (on or before). Example: "2023-01-01".
firstCommercialUseDateFromISO 8601 date stringFilter by claimed date of first use in commerce (on or after). Example: "2023-01-01".
firstCommercialUseDateToISO 8601 date stringFilter by claimed date of first use in commerce (on or before). Example: "2023-01-01".
registrationDateFromISO 8601 date stringFilter by registration date (on or after). Example: "2023-01-01".
registrationDateToISO 8601 date stringFilter by registration date (on or before). Example: "2023-01-01".
abandonmentDateFromISO 8601 date stringFilter by abandonment date (on or after). Example: "2023-01-01".
abandonmentDateToISO 8601 date stringFilter by abandonment date (on or before). Example: "2023-01-01".
renewalDateFromISO 8601 date stringFilter by renewal date (on or after). Example: "2023-01-01".
renewalDateToISO 8601 date stringFilter by renewal date (on or before). Example: "2023-01-01".
transactionDateFromISO 8601 date stringFilter by the most recent USPTO transaction date (on or after). Example: "2023-01-01".
transactionDateToISO 8601 date stringFilter by the most recent USPTO transaction date (on or before). Example: "2023-01-01".
publishedForOppositionDateFromISO 8601 date stringFilter by Official Gazette publication date (on or after). Example: "2023-01-01".
publishedForOppositionDateToISO 8601 date stringFilter by Official Gazette publication date (on or before). Example: "2023-01-01".
amendToRegisterDateFromISO 8601 date stringFilter by amend-to-register date (on or after). Example: "2023-01-01".
amendToRegisterDateToISO 8601 date stringFilter by amend-to-register date (on or before). Example: "2023-01-01".
cancellationDateFromISO 8601 date stringFilter by cancellation date (on or after). Example: "2023-01-01".
cancellationDateToISO 8601 date stringFilter by cancellation date (on or before). Example: "2023-01-01".
republished12cDateFromISO 8601 date stringFilter by §12(c) republication date (on or after). Example: "2023-01-01".
republished12cDateToISO 8601 date stringFilter by §12(c) republication date (on or before). Example: "2023-01-01".
locationDateFromISO 8601 date stringFilter by the date the file reached its current USPTO location (on or after). Example: "2023-01-01".
locationDateToISO 8601 date stringFilter by the date the file reached its current USPTO location (on or before). Example: "2023-01-01".
createdAtFromISO 8601 date stringFilter by when the record was added to the Goalie IP database (on or after). Example: "2023-01-01".
createdAtToISO 8601 date stringFilter by when the record was added to the Goalie IP database (on or before). Example: "2023-01-01".
updatedAtFromISO 8601 date stringFilter by when the record was last updated (on or after). Useful for syncing only recently changed records. Example: "2023-01-01".
updatedAtToISO 8601 date stringFilter by when the record was last updated (on or before). Example: "2023-01-01".

Pagination & sorting

FieldTypeDefaultDescription
pageinteger1Page number, 1-indexed.
pageSizeinteger25Results per page. Max 500.
sortFieldstringfilingDateField to sort by. One of: serialNumber, registrationNumber, filingDate, transactionDate, markLiteral, markDrawingCode, attorneyName, ownerName, goodsAndServices, currentStatusCode, currentStatusDate, publishedForOppositionDate, firstUseDate, firstCommercialUseDate, registrationDate, abandonmentDate, renewalDate, createdAt, updatedAt.
sortDir"asc" "desc""asc"Sort direction.

Response fields

Each record in data[] contains the following fields.

FieldTypeDescription
serialNumberstringUSPTO serial number. Unique identifier for each application.
registrationNumberstring | nullRegistration number once granted. "0000000" means not yet registered.
markLiteralstring | nullThe text of the mark. Null for purely design marks.
markDrawingCodestringCode indicating the type of mark drawing. See Drawing codes.
ownerNamestring | nullName of the current owner/registrant.
ownerAddressobject | nullStructured address: city, country, postcode, address_1, nationality_country, legal_entity_type_code.
correspondentAddressstring | nullFull mailing address of the correspondent of record.
attorneyNamestring | nullAttorney of record at the USPTO.
attorneyDocketNumberstring | nullAttorney's internal docket reference, if recorded.
domesticRepresentativeNamestring | nullDomestic representative (US contact for foreign applicants).
filingDateISO datetime | nullDate the application was filed.
transactionDateISO datetimeDate of the most recent USPTO transaction.
currentStatusCodestringCurrent application/registration status code. See Status codes.
currentStatusDateISO datetimeDate the current status was set.
registerstring (optional)Present only for the Supplemental Register: "Supplemental" once registered, "Supplemental (application)" while pending. Absent means Principal Register (or a pending Principal application). The status code alone does not distinguish the two registers.
section2fstring (optional)Present only when acquired distinctiveness under Section 2(f) is claimed: "whole mark" or "in part".
statusHistoryarrayOrdered list of all status events: { code, date, description }.
publishedForOppositionDateISO datetime | nullDate published for opposition in the Official Gazette, if applicable.
firstUseDateISO datetime | nullClaimed date of first use anywhere.
firstCommercialUseDateISO datetime | nullClaimed date of first use in commerce.
registrationDateISO datetime | nullDate the mark registered, if applicable.
amendToRegisterDateISO datetime | nullDate of amendment to the register, if applicable.
abandonmentDateISO datetime | nullDate the application was abandoned, if applicable.
cancellationCodestring | nullCancellation code, for cancelled registrations.
cancellationDateISO datetime | nullDate the registration was cancelled, if applicable.
republished12cDateISO datetime | nullDate republished under §12(c), if applicable.
renewalDateISO datetime | nullDate the registration was last renewed, if applicable.
internationalClassesstring[]Nice Classification class codes, e.g. ["025", "035"]. Empty array if unclassified.
goodsAndServicesstring | nullFull goods and services description from the application.
markDescriptionstring | nullDescription of the mark's design elements.
disclaimerstring | nullWording the owner claims no exclusive right to.
pseudoMarkstring | nullUSPTO-normalized spelling of a stylized or misspelled mark.
translationstring | nullEnglish translation of foreign wording in the mark.
transliterationstring | nullTransliteration of non-Latin characters in the mark.
designSearchCodesstring[]USPTO design search codes for figurative elements, e.g. ["050310"]. Empty array for word marks.
ownersarray | nullAll owner records with legal entity details.
classificationsarray | nullFull classification records including US class codes.
statementsCategorizedobject | nullAll application statements grouped by type.
priorRegistrationsarray | nullClaimed prior registrations.
foreignApplicationsarray | nullForeign applications claimed as priority basis.
internationalRegistrationobject | nullMadrid Protocol international registration details, if any.
madridFilingsarray | nullMadrid Protocol filing history, if any.
currentLocationstring | nullCurrent physical location at the USPTO (e.g. "PUBLICATION AND ISSUE SECTION").
lawOfficeAssignedLocationCodestring | nullAssigned USPTO law office code.
locationDateISO datetime | nullDate the file reached its current USPTO location.
employeeNamestring | nullUSPTO examining attorney assigned to the application.
headerFlagsobjectBoolean flags for application attributes (see below).
createdAtISO datetimeWhen this record was added to the Goalie IP database.
updatedAtISO datetimeWhen this record was last updated.

headerFlags

Boolean attributes of the application. Commonly useful flags:

FlagMeaning when true
trademark_inFiled as a trademark (vs. service mark, collective mark, etc.)
service_mark_inFiled as a service mark
intent_to_use_inOriginal filing basis was intent-to-use (§1(b))
use_application_currently_inCurrent basis is use in commerce (§1(a))
standard_characters_claimed_inMark is in standard characters with no design claim
color_drawing_current_inColor is currently claimed as a feature of the mark
section_8_filed_inSection 8 declaration of use has been filed
section_15_filed_inSection 15 declaration of incontestability has been filed
renewal_filed_inRenewal application has been filed
opposition_pending_inOpposition proceeding is currently pending
cancellation_pending_inCancellation proceeding is currently pending
foreign_priority_inForeign priority claim under §44(d)
supplemental_register_inOn the Supplemental Register, or a pending application amended to it (see the register field)
supplemental_register_amended_inApplication was amended from the Principal to the Supplemental Register
section_2f_inAcquired distinctiveness claimed under §2(f) for the whole mark
section_2f_in_part_inAcquired distinctiveness claimed under §2(f) for part of the mark

meta

FieldDescription
totalTotal number of records matching the query (across all pages).
pageCurrent page number.
pageSizeNumber of results returned on this page.
callsUsedTotal API calls made by your account this calendar month, including this request.
callsRemainingCalls remaining this month before your quota is exhausted.

Status codes

The currentStatusCode field uses USPTO internal codes. The most commonly encountered codes by category:

Live / Pending
CodeDescription
630New application — not yet assigned to examiner
638New application — assigned to examiner
641Non-final office action mailed
645Final refusal mailed
680Approved for publication
686Published for opposition
688Notice of allowance issued
718–734Statement of use extension requests (ITU)
744Statement of use filed
760Ex parte appeal pending
774Opposition pending
Live / Registered
CodeDescription
700Registered
701Section 8 accepted (declaration of use filed)
702Section 8 & 15 accepted — incontestable
703Section 15 acknowledged
800Registered and renewed
Dead / Abandoned
CodeDescription
600Abandoned — incomplete response
601Abandoned — express
602Abandoned — failure to respond or late response
606Abandoned — no statement of use filed
900Expired
Dead / Cancelled
CodeDescription
709Cancelled — Section 71
710Cancelled — Section 8 (failure to file maintenance)
711Cancelled — Section 7
712Cancelled by court order (Section 37)
626Registered backfile — cancelled or expired

To filter for all live registered marks, pass "currentStatusCode": ["700", "701", "702", "703", "704", "705", "800"].

Drawing codes

The markDrawingCode field indicates the form of the mark drawing submitted to the USPTO.

CodeDescription
1Typed drawing — plain word mark, no design element
2Design without color claim
3Design with color claim
4Standard character mark — word in any font, size, or color
5Standard character mark with color claim
6Special form — word combined with design element

To find only word marks (no design element), filter for markDrawingCode: "4" (standard characters) or "1" (typed drawing).

Note: Our database contains trademark metadata only — it does not store mark images or design specimens. For trademarks that consist solely of a design or logo (drawing codes 2, 3, 5, and 6), the API will return all available textual fields but no image URL or image data. To view the actual mark image, use the USPTO's TSDR portal at tsdr.uspto.gov.

Error responses

Errors return a JSON body with an error string and the appropriate HTTP status code.

{ "error": "Monthly call quota of 5000 calls exceeded. Upgrade at https://goalieip.com/subscribe" }
StatusCauseResolution
400Invalid JSON, an unrecognized parameter, a malformed date, a substring filter under 3 characters, or no narrowing filter supplied.Check the error message for the specific field. Include at least one narrowing filter (see POST /search).
401Missing, malformed, or revoked API key.Verify the Authorization header is present and the key is active in your portal. Call the www. host directly.
404Serial number not found (lookup endpoint only).Verify the serial number. USPTO serial numbers are 8 digits.
429Monthly call quota exceeded, or the per-key burst limit was hit.For quota: upgrade or wait for the 1st of next month. For a burst: honor the Retry-After header and slow down.
500Internal server error.Retry the request. If it persists, contact reid@goalieip.com.
503Search is momentarily busy (concurrency limit) or the database is warming up.Retryable — wait for the Retry-After delay and try again.
504The query exceeded the server time limit (typically a broad fuzzy search).Narrow the query (more specific term, add a filter, or use exact/contains), then retry.

Rate limits

Two limits apply. The monthly quota is enforced at the account level — all API keys on the same account share one monthly pool, and MCP tool calls draw from that same pool as REST requests. It resets on the 1st of each calendar month. A separate short-window burst limit caps how many requests a single key may make in a rolling 10-second window, protecting shared capacity; the REST endpoints and the MCP server each apply that ceiling independently, and paid tiers are far more generous.

PlanCalls / monthBurst limitOverage
Free20010 / 10sNone — requests return 429 when exhausted
API Starter ($19/mo)5,00050 / 10s+$0.0040 per call
API Professional ($49/mo)30,000100 / 10s+$0.0020 per call
API Business ($149/mo)150,000150 / 10s+$0.0015 per call

Exceeding the burst limit returns 429 with a Retry-After header (seconds) plus X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Back off and retry after the indicated delay. Burst-limited requests do not count against your monthly quota.

How overage works

Going past your included calls does not switch your API off. On a paid plan, additional calls keep working and are billed at your plan's overage rate, charged to the card on file once the billing period closes — separately from your subscription. You'll get an email receipt itemising the calls and the amount.

We email you at 80% of your allowance and again when you reach it, so overage is never a surprise. If you are regularly exceeding your plan, the next tier up costs less than the overage — that is deliberate, and the notices say so.

Overage is capped at 3× your plan's included calls, after which requests return 429. The cap exists so a misconfigured client or a looping agent cannot run up an unbounded charge; if you need it raised, contact us and we will lift it or move you to a plan that fits.

The free tier does not have overage. It stops at 200 calls and resumes at the start of the next month.

Every response includes meta.callsUsed and meta.callsRemaining so you can monitor consumption in your application. Upgrade your plan →

Frequently asked questions

Which endpoints does the API expose?

Two. POST /api/v1/trademarks/search takes a JSON body of filters and returns a paginated data array plus a meta object. GET /api/v1/trademarks/{serialNumber} returns one record. Both are versioned under /api/v1 and both speak JSON in and JSON out.

How do I authenticate an API request?

Send your key as a Bearer token in the Authorization header: Authorization: Bearer gip_live_… . Keys are 41 characters, created in your portal, and shown only once. The Bearer prefix is recommended but optional — a bare Authorization: gip_live_… is also accepted, because some clients forward an API-key field verbatim without a scheme.

How do I paginate through a large result set?

Send page and pageSize in the search body; pageSize caps at 500. Every response returns meta.total, meta.page and meta.pageSize, so you can loop until page × pageSize reaches total. Each page costs one call against your monthly quota.

What does a 429 response mean, and how should I retry?

A 429 means you exceeded the short-window burst limit for a single key. The response carries Retry-After (in seconds) plus X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset — back off for the indicated delay and retry. Burst-limited requests do not count against your monthly quota. A 429 can also mean a paid account hit its 3× overage cap.

How current is the data the API returns?

The API serves Goalie IP's own copy of the USPTO trademark dataset, ingested from USPTO bulk data and refreshed daily (occasionally a day behind) — not a live connection to USPTO systems. Each record's updatedAt field reflects its last refresh. Goalie IP is not affiliated with or endorsed by the USPTO.

Why does a request without the www host return 401 or 405?

Always call https://www.goalieip.com directly. The apex goalieip.com redirects to www, and many HTTP clients drop the Authorization header when following that redirect (returning 401) or downgrade POST to GET (returning 405).

Ready to build? View API plans and get a key →