PatentRef

Data version 20261027.2, as of 2026-10-27: the build these pages were checked against. API version 1.21.0.

Query grammar

The PatentSearch v1 grammar, as the API applies it. The OpenAPI file carries the same rules as JSON schemas: the Query schema for q, each endpoint's Fields and Sort schemas for f and s, the Options schema for o.

The request

Every endpoint accepts GET with four query parameters, or POST with the same four as a JSON body. Each parameter is a JSON value, URL-encoded on GET. The OpenAPI file gives each one a JSON schema (content application/json): q the Query schema (the grammar below), f the endpoint's <Name>Fields schema (every field name it accepts), s its <Name>Sort schema (the sortable fields), o the Options schema. On a list endpoint q is required (400 ERR_Q without it), except on the lookup endpoints (the cpc, uspc, ipc and wipo lists), which list every record when q is omitted.

Example: GET https://patentref.io/api/v1/patent/?q={"patent_id":"7861317"}&f=["patent_id","patent_title","patent_date"]

curl -G -H "X-Api-Key: $KEY" https://patentref.io/api/v1/patent/ --data-urlencode 'q={"patent_id":"7861317"}' --data-urlencode 'f=["patent_id","patent_title","patent_date","inventors.inventor_name_last"]'

Sending a request

Operators in q

Field kinds

Every field of every record schema in the OpenAPI file, the fields of nested groups and the links included, carries x-patentref-kind, the way the server treats it:

Sorting takes top-level fields only; each endpoint's <Name>Sort schema lists the ones it sorts on.

Rules that produce a 400 ERR_Q (the same list as https://patentref.io/docs/errors/ERR_Q): malformed JSON in q, f, s or o; no q on a list endpoint other than the lookup endpoints; more than one top-level key in q; an unknown field name; a field that does not belong to the endpoint; a sort on a text field without a keyword form; q or s on the lapse group; "offset" in o (the message is upstream's: 'offset' has been replaces with 'after' parameter.); a query over the cost cap; q over 16 KB (16,384 bytes) in a POST body. Prefix and wildcard operators on numeric, date and boolean fields answer 500 ERR_ES, as upstream's Elasticsearch did.

Cost cap: a query may hold at most 64 leaf criteria at depth 8 and a weighted cost of 100 units (every documented example is far below it); over the cap the API answers 400 ERR_Q naming the cost. On the long-text endpoints the cap also refuses _contains, a range or an empty _begins on the text field unless patent_id sits in the same _and (the endpoints page). The size limits are under Sending a request above: a POST body over 64,000 bytes answers 413 and a GET request line over 4,094 bytes answers 400, both from the web server in front of the API and without X-Status-Reason-Code, and q over 16 KB answers 400 ERR_Q. A statement that runs over 20 seconds, or a request over 30 seconds, answers 500 ERR_ES with the reason.

The response and paging

Shape: {"error": false, "count": <records in this page>, "total_hits": <exact number of matching records>, "<key>": [ ... ]}. The key is the endpoint's response key (the endpoints page), for example "patents". Nested groups come back as lists of objects; a group with no rows is omitted from the record.

Order of the rows in a nested group: the order of their source. For PatentsView data, inventors, assignees and attorneys come by inventor_sequence, assignee_sequence and attorney_sequence (0 first), and every other group (cpc_current, applicants, us_related_documents and the rest) in the row order of its PatentsView bulk file; for a weekly grant (the data page), the order of the grant's XML; inventor_years and assignee_years by year, oldest first. Every request against one data build gets the same order. Upstream promised no order either, and its order can differ: the saved output of the PatentsView code examples notebook lists the inventors of some patents in another order. Where the order matters, sort the rows on the group's *_sequence field.

Paging uses a cursor, never an offset. Take the sort values of the last record of a page and pass them as o.after on the next request, in the order of s. With the default sort on /patent/ (patent_id ascending):

page 1: q={"_gte":{"patent_date":"2024-01-01"}}&o={"size":1000}
page 2: same q and s, o={"size":1000,"after":["<patent_id of the last record of page 1>"]}

Walk until count is 0. The cursor is the raw sort values, so when s has two fields, after has two values. A walk is consistent inside one data build; check X-Data-Version if a walk spans a weekly refresh.

Every response carries X-Data-Version: the data_version of the search file in service (for example 20261006.5: the USPTO release date, a dot, the build sequence). Responses that never opened the data file (403, the account endpoints) carry the same value. The long text (the endpoints page) comes from a file of its own, which can be of an earlier build: X-Data-Version on those endpoints still names the search file, and X-Text-Data-Version on the same answer names the long-text file (the same value as text_data_version in GET /meta/health/), the version to cache long text under. The claim trees of /structure/claims/ (the endpoints page) are read from the long-text file too and carry both headers.