Documentation
REST API
How a platform builds on the same data your assistant searches: 40 endpoints over prior-art retrieval, patent space, and §112 claim analysis. JSON in, JSON out, one bearer token.
Base URL
https://mcp.antecedint.com/api/v1
No key yet? Sign in and one is issued immediately, free to start, or read the three-step start first. Examples below assume these two variables.
export BASE="https://mcp.antecedint.com/api/v1"
export ANTECEDINT_API_KEY="ak_live_..."Sign in and your free key is issued on the spot.
Sign inAll endpoints
The whole surface. Free endpoints cost nothing against your quota beyond the request itself.
| Endpoint | Does | Cost |
|---|---|---|
| POST /context | Route a question to the walks that answer it and return documents | Metered |
| GET /gardens | Every garden and every question, with what each holds and what is being built | Free |
| GET /gardens/:id | One data garden | Free |
| POST /prior-art | Search 10.5M US patents for prior art against a claim | Metered |
| POST /prior-art/claims | Fetch claim text and abstracts for specific applications | Metered |
| GET /patent-map/patent/:appNum | Patent position and its nearest semantic neighbours | Metered |
| GET /patent-map/patent/:appNum/citations | Cited prior art resolved to patent-space positions | Metered |
| POST /patent-map/locate | Locate free text or an application in patent space | Metered |
| GET /patent-map/whitespace | Ranked gaps in patent space | Free |
| GET /patent-map/points | Sampled background point cloud | Metered |
| POST /feedback | Report a data error | Free |
| POST /feedback/search | Judge a search's results and suggest better ones | Free |
| GET /feedback | List data error reports | Free |
| POST /claim-validation/antecedent-basis | Check a draft claim set for antecedent-basis defects | Free |
| GET /claim-validation/antecedent-basis/:appNum | Check the filed claims of an application | Metered |
| POST /claim-validation/support | Map claim terms to their specification support | Metered |
| GET /claim-validation/support/:appNum | Support map for a filed application and its parents | Metered |
| POST /warmup | Start the inference hub ahead of a search | Free |
| GET /warmup | Whether the inference hub is warm | Free |
| GET /usage | What this key has spent and has left, and when each limit resets | Free |
| POST /jobs/read | Read a background job's status and result | Free |
| GET /jobs | List this key's recent background jobs | Free |
| GET /areas | List the areas of law | Free |
| GET /capabilities | List the capabilities in an area, garden or path | Free |
| GET /capabilities/:id | Describe one capability | Free |
| GET /status | Usage and model warmth for this key | Free |
| POST /status | Start the search models, then report usage and warmth | Free |
| GET /references | List the dated reference material | Free |
| GET /references/read | Read one reference by uri | Free |
| GET /patent-intel/cpc/:code | CPC symbol with its art-unit distribution and children | Metered |
| GET /patent-intel/classification/:number | CPC classification for a publication or application number | Metered |
| GET /patent-intel/art-unit/:artUnit | Art-unit profile, statistics and examiner roster | Metered |
| GET /patent-intel/examiners | Search examiners by name or art unit | Metered |
| GET /patent-intel/examiner/:examiner | Examiner statistics and behavioural profile | Metered |
| GET /guidance/mpep/:sectionId | One MPEP section with its rules and required examiner actions | Metered |
| GET /guidance/epo/:sectionId | One EPO Guidelines section with its rules and citations | Metered |
| GET /guidance/form-paragraph/:code | One office-action form paragraph, with its statute and MPEP section | Metered |
| GET /guidance/form-paragraphs | Form paragraphs filtered by rejection type or MPEP section | Metered |
| GET /guidance/graph/:nodeId | One-hop cross-references into and out of a guidance section | Metered |
| GET /guidance/design-code/:code | One USPTO design search code | Metered |
Context
One question in; the data gardens that hold its answer run and return documents with their measured limits.
Route a question to the walks that answer it and return documents
Route a question to the walks that answer it and return their documents.
Free and open. Over MCP on your own key the search has no daily limit, only the plan's per-minute ceiling. Over REST, the plan's daily allowance applies (200 on the free plan), and without a key a caller gets 25 free searches a day from one address. free_search in the answer says how many are left and when they reset; it is absent when there is no daily limit. The free search includes the dig: the independent claims of the top hits and the passage closest to each element. rerank: true makes it a paid search (10 credits, a key required) that does not use the free allowance. MCP hosts can add the same search with no sign-in at https://mcp.antecedint.com/api/v1/mcp/open.
GET /gardens lists the gardens (the tuned data) and the questions (the walks over them). This call reads the question for routing signals, runs every question weighted at or above 0.5 (at most three) in parallel, and answers with one entry in answers[] per question: the gardens it walked, its documents, count and candidates, notes on what it did, its timings, and error when it could not run. gardens{} carries every garden any answer walked, keyed by id and stated once: what it holds (holds, each figure with n, date and source), what is being built on it (roadmap), and what serves it today (served_by). routing says how the questions were chosen (signal, pinned or fallback), with the signals that fired and the facts read out of the text. not_covered lists questions left out and why, and roadmap items that bear on the question, such as non-patent literature not being indexed.
A walk over an index garden states its time policy. asOf is the day art must predate, strictly: the store admits rows dated before it and refuses rows with no date, and the answer reports time_policy (the day, the column it was decided on, whether the store applied it and the bound it applied) with time_filter_violations (returned documents dated on or after the day; must be 0) and each document's decided_on and time_check. excludeFamilyOf drops the application's family and the answer reports exclusion with family_leaks, same_app_hits and no_family_id_hits (rows that carry no family id and so could not be excluded by it), with each document's exclusion_check.
Walks that need the encoder are skipped when it is cold and waitForHub is not set, with a HUB_COLD error carrying the get_status warm-up remedy and the exact re-call; the health check that decided this has already started the instance.
Documents share one shape across gardens: id, type and unit, title, snippet, score and score_kind, source (the garden, the question that walked it, and the primitive tool that reads it in full), country, reachable, filing_date, url and ref (the native keys a follow-up call needs). Snippets are clipped to the budget and never reordered; truncated says when an answer was cut.
Body
| Name | Type | Description |
|---|---|---|
| question req | string, 8–20000 chars | The question as asked, or claim text. Claim text routes to prior_art_claim; a numbered claim set with dependencies also routes to claim_defects. |
| questions | string[], max 4 | Question types from GET /gardens. Pins the set and skips routing; signals still run so the pinned walks get the facts read from the text. |
| maxDocuments | integer, 1–100 | Documents per answer. Defaults to 10. |
| budget | integer, 2000–120000 | Character budget for the documents across every answer, split by routing weight. Documents are clipped from the tail, never reordered. Defaults to 24000. |
| snippets | boolean | false returns ids, refs, scores and dates only, which is what an evaluation or a dedup pass reads. Defaults to true. |
| asOf | string, ^\d{4}(-\d{2}(-\d{2})?)?$ | The day art must predate, strictly (YYYY, YYYY-MM or YYYY-MM-DD; a year or a month resolves to its first day). Pass the priority date of the claim being searched. |
| filedBefore | string, ^\d{4}(-\d{2}(-\d{2})?)?$ | The older name for asOf, honoured when asOf is absent. |
| filedAfter | string, ^\d{4}(-\d{2}(-\d{2})?)?$ | Lower date bound for the index walks. |
| excludeFamilyOf | string, ^\d{7,12}$ | US application number whose patent family the index walks drop. |
| cpc3 | string[], max 20 | Restrict the index walks to these CPC subclasses. Excludes unclassified references, so leave it unset on a first pass. |
| rerank | boolean | Run the ColBERT reranker in prior_art_claim. Paid: 10 credits, and it needs a key. Slower, and loads a second model on a cold hub. Defaults to false. |
| dig | boolean | prior_art_claim reads the independent claims of the top three hits and, for the top two, the passage closest to each element of the claim, returned in answers[i].dig. false skips it. Defaults to true. |
| hyde | boolean | Force the query rewrite into patent language on or off; unset lets the walk decide (on for a short description, off for a claim). |
| waitForHub | boolean | Wait for a cold encoder instead of skipping the index walks; about 75 s on the evaluation tier. Defaults to false. |
Responses
| 200 | { question, routing, answers[], gardens{}, not_covered[], credits, budget, timings, request_id, timestamp }. routing.via is signal, pinned or fallback. Each entry in answers[] carries question_type, gardens_walked[], documents[], count, candidates, truncated, notes[], timings and error (null, or a HUB_COLD payload with a remedy); over an index garden also time_policy, time_filter_violations, undated_returned and exclusion. Each entry in gardens{} carries served_by, pool, units, holds[], roadmap[], notes[] and walked_by[]. | |
| 400 | VALIDATION_ERROR | question is missing or out of range, or a parameter failed its rule. |
| 400 | UNKNOWN_QUESTION | A pinned type is not registered; known lists the types. |
| 401 | KEY_REQUIRED | rerank was asked for without a key. |
| 429 | FREE_SEARCH_LIMIT | The day's free searches are used, per key, per address, or (without a key) across every caller, which free_search.per names as key, ip or all; free_search.resetAt says when they come back. |
| 429 | USAGE_LIMIT_EXCEEDED | A paid (reranked) search found the key's credit or request ceiling reached. |
| 500 | INTERNAL_ERROR | Routing itself failed. A walk that fails answers 200 with error on its own answer. |
curl -sS "$BASE/context" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"question":"What does MPEP 2106 require an examiner to establish before rejecting a claim under 101?","maxDocuments":5}'This one spends real model inference on each call. Run it in the sandbox →
{
"question": "What does MPEP 2106 require an examiner to establish before rejecting a claim under 101?",
"routing": {
"via": "signal",
"questions": [{ "type": "examination_rule", "weight": 1, "reason": "mpep_section: MPEP 2106", "primary": true }],
"signals": [{ "name": "mpep_section", "evidence": "MPEP 2106" }],
"facts": { "mpepSection": "2106", "rejectionType": "101" }
},
"answers": [{
"question_type": "examination_rule",
"question": "Which rule obliges this office action, here and at the EPO?",
"gardens_walked": ["ip.mpep-epo"],
"documents": [{ "id": "mpep-2106", "type": "section", "unit": "section", "title": "Patent Subject Matter Eligibility", "snippet": "…", "source": { "garden": "ip.mpep-epo", "question_type": "examination_rule", "tool": "get_mpep_section" } }],
"count": 1,
"error": null
}],
"gardens": {
"ip.mpep-epo": {
"id": "ip.mpep-epo", "kind": "text", "title": "MPEP and EPO Guidelines",
"served_by": { "kind": "production", "engine": "guidance", "store": "firestore", "dataset": "guidance" },
"holds": [{ "fact": "MPEP sections", "kind": "count", "value": 1873, "n": 1873, "measured": "2026-09-08", "source": "loader manifest, scripts/ops/guidance/plan.js" }],
"roadmap": [], "walked_by": ["examination_rule"]
}
},
"not_covered": [],
"credits": { "charged": 10, "by_question": { "examination_rule": 1 } },
"timestamp": "2026-09-16T09:10:04.118Z"
}Data gardens
The garden registry as data: what each holds, counted and dated, and what is being built on it.
Every garden and every question, with what each holds and what is being built
Every garden and every question Ask Antecedint can route to.
A garden entry carries id, corpus, kind (index, graph, map, table or text), title, description, tuned_for, units, the tools that read it, served_by (what answers for it today: a production store, or a program garden version with its garden_version_id, spec_hash and pool_id), pool, holds, roadmap, notes and walked_by (the question types over it). A hold is a measurement: fact, kind (count, rate or score), value, n, measured and source, with population on a score. A count is the garden's size on that date; a rate or a score was measured on the named population and is not a measurement of the live tool. A garden with no score hold has not been benchmarked, and the absence is the statement.
A question entry carries type, corpus, question, title, routingDescription, the gardens it walks, scope, hub, cost, timeoutMs, checks (the program check tools whose semantics the walk implements) and examples.
planned_areas names the corpora with no garden yet, with their phase.
Query parameters
| Name | Type | Description |
|---|---|---|
| corpus | string, one of ip, prosecution, guidance | Only gardens and questions over this corpus. |
Responses
| 200 | { gardens[], questions[], count, planned_areas[], timestamp }. count is the number of gardens. | |
| 400 | VALIDATION_ERROR | corpus is not a known key. |
curl -sS "$BASE/gardens?corpus=patents" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"One data garden
One garden by id, in the same shape as the list, with the questions that walk it.
Path parameters
| Name | Type | Description |
|---|---|---|
| id req | string, ^[a-z]+\.[a-z-]+$ | Garden id, e.g. ip.prior-art. |
Responses
| 200 | The garden record, plus questions[]: the walks over it. | |
| 400 | VALIDATION_ERROR | id is not shaped corpus.slug. |
| 404 | NOT_FOUND | No garden has this id; known lists the ids. |
curl -sS "$BASE/gardens/ip.prior-art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Prior-art search
Two-stage neural retrieval over 10.5M US applications.
Search 10.5M US patents for prior art against a claim
Semantic prior-art search for a claim set. A fine-tuned dense encoder retrieves candidates from the Index-1 vector space, and a citation-graph channel contributes references an embedding alone would miss.
Each result carries its title, abstract and claims. It does not carry a specification body: this used to promise background, summary and detailed description, which was true while the route downloaded each hit's SPEC document from USPTO and ran OCR and a model over it on the request path. That cost 18-55s per search and came off the live path on 2026-08-24. Context now comes from the corpus we already hold, and description_text is unpopulated there, so those sections are not available at any latency.
metadata.context_coverage reports how many results actually carried each part, so a thin answer is distinguishable from a failed lookup.
Either claims or abstract satisfies the request, but claim text retrieves better: the encoder was trained on abstract [SEP] claim1, so supplying both matches the document representation the index was built from.
metadata.total_cost reports what the call actually spent on model inference, in USD. Latency runs 20-60s uncached and is dominated by specification parsing, not by retrieval; rerank adds to it.
Body
| Name | Type | Description |
|---|---|---|
| claims | string, 10–20000 chars | Claim text; independent claim 1 works best. Required unless abstract is given. |
| abstract | string, 0–10000 chars | Abstract or invention summary. Required unless claims is given. |
| count | integer, 1–100 | Number of references to return. Defaults to 50. |
| useReranking | boolean | Run the ColBERT late-interaction reranker over the top candidates. Higher precision, slower. Defaults to false. |
| includeClaims | boolean | Return full claim text and abstract sections for every reference. Off by default: the lookup is a BigQuery query with a job-submission floor of roughly a second whatever it scans, and a caller that ranks first and reads one or two pays that second for thirteen references it never opens. Fetch the ones you want with POST /prior-art/claims. title_source on each result reads index when the title came from the vector index, whose titles were rewritten from publication records on 2026-09-13, or lookup when claims were fetched and the BigQuery row supplied it. Defaults to false. |
| hyde | boolean | Rewrite the query into patent language before searching. A model drafts a hypothetical abstract and first claim for what you described, and that is searched instead. Worth setting when you have a description rather than claim text: the index holds formal claim language, and a plain-English query has to cross that gap unaided. Not worth setting when you already have a claim, which is the strongest query available. Adds about two seconds. metadata.hyde returns the generated text, because a rewritten query changes what was searched and the results cannot be judged without it. Defaults to false. |
| hybrid | boolean | Also run BM25 over patent titles and abstracts and fuse the rankings. The encoder was trained on meaning, so it does not guarantee an exact phrase outranks a paraphrase; when you use a term of art, that term is the strongest signal available and dense search alone discards it. Measured: US-11389765-B2 was absent from the dense top 20 for a gyroid heat exchanger query and is rank 1 on BM25 over titles. Each result gains matched_legs, how many of the three retrievers found it, which is a sharper signal than a similarity score compressed into a 0.05 band. Defaults to false. |
| forceReprocess | boolean | Bypass and overwrite every cache layer, re-parsing specifications that were already parsed. Costs real model spend on each call and is meant for reprocessing after a parser change, not for normal use. Defaults to false. |
| filedBefore | string | Exclude references filed on or after this date. Prior art must predate the application it is cited against, so supply the priority date of the invention you are searching for; without it the results include later filings, which cannot be cited. YYYY, YYYY-MM or YYYY-MM-DD, evaluated to the day: 2005-12-23 excludes everything filed that day or later. A bare year or month means its first day. The filter stage in metadata.timings reports the bound as applied. References with no recorded filing date (2.5% of the index) are excluded by any date bound, since they cannot be shown to satisfy it. |
| filedAfter | string | Exclude references filed on or before this date. For narrowing to a period, not for prior art. A bare year or month means its last day. |
| excludeFamilyOf | string, ^\d{7,12}$ | A US application number whose patent family is dropped from the results. A claim searched against the index finds its own continuations first, and a date bound only removes the ones filed after it. The filter stage reports the family id resolved, or that the number is not in the index and nothing was excluded. |
| cpc3 | string[] | Restrict to these CPC subclasses, e.g. ["H01M","F28D"]. Useful for a second pass once a first search has shown which art areas matter. Note that CPC data covers roughly 65% of the index, and a reference carrying no CPC is excluded by this filter rather than ranked lower — so narrowing by subclass also drops everything unclassified. Prefer it for a follow-up pass, not a first search. |
| country | string | Restrict to one country code. Only US is served: EP records share application numbers with US ones in the index and are left out of every search, so any other value returns no results. |
Responses
| 200 | { success: true, data: { specifications[], metadata } }. metadata carries credits_charged (what the call cost you), total_cost (USD we spent on model inference, not your charge; 0 on this path), context_source (vector-metadata, or vector-metadata+bigquery-claims when includeClaims fetched claims), request_id, and timestamp. | |
| 400 | Neither claims nor abstract was supplied, both were empty, count fell outside 1-100, forceReprocess was not a boolean, or a date bound was not an ISO date. A malformed date is refused rather than dropped: a prior-art search that silently loses its cutoff returns references that postdate the invention while appearing to have honoured the request. The body is { success: false, error } with no code field. | |
| 500 | Search failed. The body carries request_id; quote it when reporting. |
curl -sS "$BASE/prior-art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"claims":"1. A method of cooling a battery pack, comprising...","count":25}'This one spends real model inference on each call. Run it in the sandbox →
{
"success": true,
"data": {
"specifications": ["one structured specification per reference, ranked; elided here"],
"metadata": {
"requested_count": 25,
"returned_count": 25,
"cached_count": 19,
"newly_processed_count": 6,
"cache_hit_rate": 0.76,
"processing_time_seconds": 34.2,
"textract_cost": 0.04,
"bedrock_cost": 0.14,
"total_cost": 0.18,
"request_id": "req-1755162764108-k3f9a2b1c",
"timestamp": "2026-08-14T09:12:44.108Z"
}
}
}Fetch claim text and abstracts for specific applications
Full text for references you already have.
WHY THIS IS SEPARATE FROM THE SEARCH The claims lookup is a BigQuery query, and BigQuery charges roughly a second of job submission whatever it scans. Folding it into every search made the ranking wait on text the caller had not asked for yet: fifteen references fetched in full so one or two could be read. Splitting it lets a search answer in the time the search actually takes, and puts the second on whoever wants the text.
Batched deliberately. One call for the three references worth reading costs the same second as one call for one, and the alternative is three round trips that each pay it.
Endpoint docs live in the @endpoint block; see docs/api/doc-comments.md.
Body
| Name | Type | Description |
|---|---|---|
| appNumbers req | string[] | US application numbers to fetch, digits only (16115156), 1 to 25 per call. These are the application_number values a search returns. |
| format | string | parsed returns claims only as the structured claims array. raw also includes the unparsed claim blob as a section, which is the same text a second time and roughly doubles the response. Use raw only when the parse itself is in question. Defaults to parsed. |
| independentOnly | boolean | Return only independent claims. Triage usually needs claim 1, and a record can carry two dozen. The number dropped is reported as metadata.claims_withheld so a short answer cannot be mistaken for a short patent. Defaults to false. |
Responses
| 200 | { success: true, data: { specifications[], metadata } }. One entry per application number that was found, in the order asked for. An application with no row in the lookup table is reported in metadata.not_found rather than returned empty, because "this patent has no claims on file" and "we could not fetch them" are opposite conclusions. | |
| 400 | appNumbers was missing, empty, not an array, held something that is not a digit string, or held more than 25 entries. | |
| 500 | The lookup failed. The body carries request_id. |
curl -sS "$BASE/prior-art/claims" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"appNumbers":["16115156","17003222"]}'This one spends real model inference on each call. Run it in the sandbox →
{
"success": true,
"data": {
"specifications": ["one structured specification per application; elided here"],
"metadata": {
"requested": 2,
"returned": 2,
"not_found": [],
"lookup_ms": 1120,
"request_id": "req-1755162764108-k3f9a2b1c"
}
}
}Patent space
Positions, neighbours, citations and gaps in one shared coordinate frame.
Patent position and its nearest semantic neighbours
One call frames a patent's neighbourhood, which is the payload behind the display-mode embed: { self, neighbors[], count }.
self is null when the application has no vector in the index, which happens for pre-corpus, design, and plant applications. The application can still be absent entirely, and that answers 404 rather than a null self.
Neighbour order is cosine similarity in the embedding space, not 3D distance. Semantically closest comes first; the coordinates are for laying them out, not for re-deriving the ranking. Distance in the projection and rank in the list disagree often enough that sorting by one and labelling it the other will mislead.
Path parameters
| Name | Type | Description |
|---|---|---|
| appNum req | string, ^\d{7,12}$ | US application number, digits only. |
Query parameters
| Name | Type | Description |
|---|---|---|
| topK | integer, 1–100 | Number of neighbours to return. Defaults to 20. |
Responses
| 200 | { appNum, self, neighbors[], count, timestamp }. Each neighbour is a point plus score, the cosine similarity. | |
| 400 | VALIDATION_ERROR | appNum is not 7-12 digits, or topK is outside 1-100. |
| 404 | NOT_INDEXED | No vector is indexed for this application. |
| 502 | UPSTREAM_ERROR | The vector index could not be reached. |
curl -sS "$BASE/patent-map/patent/16123456?topK=5" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"appNum": "16123456",
"self": {
"appNum": "16123456",
"x": 4.771,
"y": -1.02,
"z": 2.503,
"section": "H",
"artUnit": "1727",
"filingDate": "2019-05-14"
},
"neighbors": [
{
"appNum": "16412088",
"x": 4.802,
"y": -1.114,
"z": 2.397,
"section": "H",
"artUnit": "1725",
"filingDate": "2019-08-02",
"score": 0.9012
}
],
"count": 5,
"timestamp": "2026-08-14T09:12:44.108Z"
}Cited prior art resolved to patent-space positions
The application's cited prior art, resolved to map positions. Each point carries examiner: true when the reference came from the examiner rather than from the applicant's IDS, which is the distinction that matters: examiner citations are what was actually applied against the application.
Examiner-cited references lead the list and are never dropped. Applicant citations fill the remainder up to 150 references total, so a 400-reference IDS cannot balloon the response.
Pass year, the citing application's filing year, when you know it. It narrows the underlying lookup and makes the call measurably cheaper.
References with no vector in the index are counted in notIndexed and omitted from points. Positions on this API are always exact index coordinates; nothing is placed approximately to fill a gap.
Path parameters
| Name | Type | Description |
|---|---|---|
| appNum req | string, ^\d{7,12}$ | US application number, digits only. |
Query parameters
| Name | Type | Description |
|---|---|---|
| year | integer, 1970–2035 | Filing year of the citing application. Optional, and makes the lookup faster when supplied. |
Responses
| 200 | { appNum, points[], count, citedTotal, notIndexed, examinerTotal, examinerNotIndexed, timestamp }. Each point carries examiner and title alongside the coordinates. citedTotal counts distinct US applications cited, a reference both the examiner and the applicant cited counted once, as the examiner's; foreign patents and non-patent literature are not counted here (ask's examiner_citations walk counts them, and says how many of each). examinerTotal is how many of citedTotal the examiner cited, and examinerNotIndexed how many of those have no position in the index. | |
| 400 | VALIDATION_ERROR | appNum is not 7-12 digits, or year is implausible. |
| 502 | UPSTREAM_ERROR | The citation service or vector index could not be reached. |
curl -sS "$BASE/patent-map/patent/16123456/citations?year=2019" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Locate free text or an application in patent space
Semantic search into the space. Free text is embedded and matched against the index; given an appNum instead, the application's own abstract and first claim are joined as abstract [SEP] claim1 and used as the query, which reproduces the document representation Index-1 was built from and retrieves better than anything typed by hand.
Alongside the nearest patents it returns landing, a rank-weighted centroid of the top 8 hits. That is where the query sits in the space and the anchor a camera should fly to. It is not a patent and has no application number.
This is the one endpoint on the patent-map router that spends an embedding-hub encode per call, so it is the one that does not answer from cache.
Body
| Name | Type | Description |
|---|---|---|
| query | string, 8–4000 chars | Free-text technical description. Supply either this or appNum; query wins when both are present. |
| appNum | string, ^\d{7,12}$ | Locate an application by its stored vector. The application itself is excluded from neighbors. |
| topK | integer, 1–100 | Number of nearest patents to return. Defaults to 20. |
Responses
| 200 | { landing: {x,y,z}, self?, neighbors[], count, located_by, timestamp }. located_by is stored_vector (the index holds the application: landing is its stored point, returned as self, and neighbour scores are against the document vector), re_encoded_text (it does not: the text was encoded as a query, scores top out near 0.87 and landing is a centroid; a note says so), or query_text. | |
| 400 | VALIDATION_ERROR | Neither query nor appNum was supplied, or one of them failed its length or format rule. |
| 404 | NOT_FOUND | No text could be found for the application, or no indexed match carried map coordinates. |
| 502 | UPSTREAM_ERROR | The embedding hub or vector index could not be reached. |
| 503 | MAP_COORDINATES_UNAVAILABLE | The vector index this deployment is configured against does not store UMAP coordinates, so nothing can be placed in patent space. Prior-art search is unaffected. |
curl -sS "$BASE/patent-map/locate" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"query":"phase-change material for battery thermal management","topK":10}'{
"landing": { "x": 4.812, "y": -1.093, "z": 2.446 },
"neighbors": [
{
"appNum": "16412088",
"x": 4.771,
"y": -1.02,
"z": 2.503,
"section": "H",
"artUnit": "1727",
"filingDate": "2019-05-14",
"score": 0.8814
}
],
"count": 10,
"timestamp": "2026-08-14T09:12:44.108Z"
}Ranked gaps in patent space
The analysed whitespace atlas: gaps in patent space, ranked by opportunity, descending. Built for the inventor-facing question of where the open ground is.
Each void carries an id, a position in the same coordinate frame as every other endpoint on this router, a radius, an opportunity score from 0 to 1, a CPC section, the bordering CPC codes with their fractions and titles, a temporal profile giving the median filing year of the surrounding art and a hot flag, a generated summary of what is missing there, the nearest bordering patents as exemplars, and the assignees active nearby.
Each exemplar carries appNum, dist, title and country; a non-US one also carries reachable: false, because its number is not a US serial and the claims and specification endpoints cannot resolve it. An exemplar the search index does not hold keeps title: null and says so in title_note. When the atlas names no assignees for a void, assignees holds those of its exemplars and assignees_source reads exemplars: the six nearest bordering patents, not a survey of the area.
The atlas is a precomputed artifact, rebuilt on its own schedule rather than on request, and cached for 30 minutes once loaded. Two calls a minute apart return the same voids.
Query parameters
| Name | Type | Description |
|---|---|---|
| limit | integer, 1–500 | Maximum voids to return. Defaults to 100. |
| section | string, ^[A-HY]$ | Restrict to one CPC section letter. |
| minOpportunity | number, 0–1 | Drop voids scoring below this. Defaults to 0. |
Responses
| 200 | { voids[], count, total, timestamp }. total counts everything matching the filters; count is how many limit allowed through. | |
| 400 | VALIDATION_ERROR | limit, section, or minOpportunity is out of range. |
| 404 | NOT_FOUND | The whitespace atlas has not been built. |
| 502 | UPSTREAM_ERROR | The atlas could not be read from storage. |
curl -sS "$BASE/patent-map/whitespace?section=G&minOpportunity=0.6&limit=20" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Sampled background point cloud
A sampled background cloud for context rendering, up to 50,000 points per request.
The sample reads the map's point chunks in stored order. It is stable across calls, and it is not random: the first 10,000 points are the same 10,000 points every time, and they are not a representative sample of the corpus. Filter server-side with section and artUnit rather than over-fetching and filtering client-side, because the scan stops at a fixed budget regardless of how many points survive your filter.
That budget is 1,500,000 scanned points. A filter narrow enough to exhaust it before collecting limit points returns what it found with truncated: true. Treat that flag as a signal to narrow differently rather than to retry, since the scan is deterministic and a retry returns the same partial sample.
Query parameters
| Name | Type | Description |
|---|---|---|
| limit | integer, 100–50000 | Points to return. Defaults to 10000. |
| section | string, ^[A-HY]$ | Restrict to one CPC section letter. |
| artUnit | string, ^\d{1,4}$ | Restrict to an art-unit prefix. |
Responses
| 200 | { points[], count, truncated, timestamp } | |
| 400 | VALIDATION_ERROR | limit, section, or artUnit is out of range. |
| 502 | UPSTREAM_ERROR | The map's point chunks could not be read from storage. |
curl -sS "$BASE/patent-map/points?limit=5000§ion=H" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Data feedback
Report a wrong value or missing data in a garden. Free, up to 100 reports a day; an accepted report earns credits.
Report a data error
File a report of a wrong value or missing data in a garden. Free, never counted against the request limits, and capped at 100 a day per account. With a key, a report a decision model finds specific and new earns 2 credits at once (up to 20 a day), and one a reviewer accepts earns 10, 50 or 200 more; a rejected one or a repeat of an accepted one earns nothing. With anonymous true, reviewers and the export never see who filed it and it earns no credits. Without a key a report is filed anonymously, earns no credits, and is capped at 20 a day per address. Reports are stored and read by people: describe the data error and leave out personal or confidential details.
Body
| Name | Type | Description |
|---|---|---|
| garden req | string, ^[a-z]+\.[a-z-]+$ | The garden the value came from, such as ip.classification. |
| kind req | string, one of incorrect_value, missing_data, wrong_link, unclear, other | What is wrong, or unclear for something you cannot explain. |
| evidence req | string, 10–4000 chars | What the source says and where. |
| document_id | string, 1–200 chars | The document, record or entry. |
| field | string, 1–200 chars | The field or label, or the text of a hold. |
| current_value | string, 0–2000 chars | The value as served. |
| proposed_value | string, 0–2000 chars | The value it should be. |
| sources | string[], max 5 | Links to the source record. |
| certainty | string, one of confirmed, likely, unsure | How sure the filer is. Unsure reports are welcome. |
| anonymous | boolean | Hide who filed it from reviewers and the export. An anonymous report earns no credits. Defaults to false. |
| sources[] | string, ^https?:\/\/ | One link, http or https, at most 500 characters. |
Responses
| 200 | { feedback_id, status, submitted_today, daily_cap, reward_policy }. | |
| 400 | VALIDATION_ERROR | A field is missing or out of bounds. |
| 400 | UNKNOWN_GARDEN | No garden by that id. |
| 403 | ACCOUNT_REQUIRED | A key was sent and it belongs to no account. File without a key instead. |
| 409 | DUPLICATE | This account already filed this report and it is open or accepted. |
| 429 | DAILY_LIMIT | This account has filed 100 reports today, or this address 20 without a key. |
| 503 | ANONYMOUS_UNAVAILABLE | Anonymous filing is unavailable on this deployment. |
curl -sS -X POST "$BASE/feedback" -H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"garden":"ip.classification","kind":"incorrect_value","document_id":"US11322549B2","field":"main_cpc","proposed_value":"H01M 10/0562","evidence":"The grant lists H01M 10/0562 first on its front page."}'Judge a search's results and suggest better ones
Judge a search: say which results served were relevant and name better ones found elsewhere (a patent or application, or non-patent literature by DOI, URL or citation), so the ranking can be measured and retrained. Searches are not stored, so the query is kept only if sent here, and sealed when it is; leave it out to judge the results alone. Same queue, daily cap and credits as a data error report: free, uncounted, 2 credits at once when the screen finds it specific and new (up to 20 a day), more when a reviewer accepts it. Reports are stored and read by people: leave out personal or confidential details.
Body
| Name | Type | Description |
|---|---|---|
| garden req | string, ^[a-z]+\.[a-z-]+$ | The garden the search read, such as ip.prior-art. |
| tool | string, ^[a-z][a-z0-9_]{1,60}$ | The tool that ran the search, such as search_prior_art or ask. |
| query | string, 0–20000 chars | The query or claim as searched. Optional, and kept only if sent. |
| as_of | string, ^\d{4}(-\d{2}(-\d{2})?)?$ | The date bound the search used. |
| filters | object | Other filters the search used (cpc3, country, excludeFamilyOf). |
| shown | object[], max 100 | The results as served, in rank order, each judged or not. |
| shown[].id req | string, 1–200 chars | The result's id as served. |
| shown[].rank | integer, 1–1000 | Its rank in the answer. |
| shown[].judgement | string, one of highly_relevant, relevant, partly_relevant, not_relevant | How relevant it is. |
| shown[].why | string, 0–1000 chars | Why. |
| better | object[], max 25 | Results the search should have returned. |
| better[].id | string, 1–200 chars | A patent, publication or application number. |
| better[].npl | object | Non-patent literature: title, doi, url, authors, year, citation. |
| better[].judgement | string, one of highly_relevant, relevant, partly_relevant, not_relevant | How relevant it is (default relevant). |
| better[].rank_wanted | integer, 1–1000 | Where it should have ranked. |
| better[].why | string, 0–1000 chars | Why it is better. |
| better[].passage | string, 0–2000 chars | The passage that discloses the point. |
| note req | string, 10–4000 chars | What the judgement rests on. |
| sources | string[], max 5 | Links to the better results. |
| certainty | string, one of confirmed, likely, unsure | How sure the filer is. |
| anonymous | boolean | Hide who filed it from reviewers and the export. Earns no credits. Defaults to false. |
Responses
| 200 | { feedback_id, status, query_stored, judged, better, submitted_today, daily_cap, screen, reward_policy }. | |
| 400 | VALIDATION_ERROR | A field is missing or out of bounds. |
| 400 | UNKNOWN_GARDEN | No garden by that id. |
| 400 | NOTHING_JUDGED | No result judged and no better result named. |
| 403 | ACCOUNT_REQUIRED | A key was sent and it belongs to no account. File without a key instead. |
| 409 | DUPLICATE | This account already filed this judgement and it is open or accepted. |
| 429 | DAILY_LIMIT | This account has filed 100 reports today, or this address 20 without a key. |
curl -sS -X POST "$BASE/feedback/search" -H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"garden":"ip.prior-art","tool":"search_prior_art","shown":[{"id":"16412088","rank":1,"judgement":"not_relevant"}],"better":[{"npl":{"title":"Phase change materials for battery thermal management","doi":"10.1016/j.jpowsour.2015.01.030"},"judgement":"highly_relevant","rank_wanted":1,"why":"Discloses the PCM layer in contact with the cells and a conductive lattice."}],"note":"The top result is about electrolyte additives; the paper discloses both limitations of the claim."}'List data error reports
The reports this account has filed, newest first, each with its status, the reward tier and credits granted when accepted, and the reviewer's note; with how many were filed today against the daily cap and the credits earned in all. With id, one report.
Query parameters
| Name | Type | Description |
|---|---|---|
| status | string, one of submitted, accepted, rejected, duplicate | Only reports with this status. |
| id | string, ^fb_[A-Za-z0-9_-]{20}$ | One report. |
Responses
| 200 | { feedback[], submitted_today, daily_cap, credits_earned, reward_policy }, or one report with id. | |
| 403 | ACCOUNT_REQUIRED | The key belongs to no account. |
| 404 | NOT_FOUND | No report by that id for this account. |
curl -sS "$BASE/feedback?status=accepted" -H "Authorization: Bearer $ANTECEDINT_API_KEY"§112 claim validation
Antecedent basis and claim-term support, for drafts and for filed applications.
Check a draft claim set for antecedent-basis defects
Check a claim set for §112(b) antecedent-basis defects. Finds definite recitations ("the widget", "said widget") with no earlier indefinite recitation in the same claim or in a claim it depends from, plus double inclusions, plural and singular mismatches, and improper dependencies.
Implicit antecedent basis under MPEP 2173.05(e) is suppressed, so "the outer surface of the housing" is not flagged when the housing was properly introduced. Pass includeSuppressed to see what the suppression rules removed and which rule removed each one, which is how you audit the checker rather than trust it.
Findings are graded. high means no plausible antecedent exists anywhere in the set; low means one probably exists under different wording and a human should look.
Deterministic, no LLM, no network, and sub-millisecond per claim, so a draft editor can call it on every keystroke.
Body
| Name | Type | Description |
|---|---|---|
| claims req | object[], max 300 | The claim set, in order. Each entry is { number?, text }; a bare string is accepted in place of an object, and a missing number is filled from the array position. |
| claims[].text req | string, 10+ chars | Claim text without the leading number. |
| claims[].number | integer, 1 and up | Claim number. |
| minSeverity | string, one of high, medium, low | Lowest severity to report. Defaults to low. |
| includeSuppressed | boolean | Also return the candidates the implicit-basis rules suppressed, each with the rule that killed it. Defaults to false. |
Responses
| 200 | { available: true, source: "request", issues[], claims[], dependencies[], stats }. issues[] is the flat list of every defect found; each entry of claims[] also carries its own issues[]. stats holds issueCount, bySeverity and byType. An empty issues[] means the claim set is clean, and is the only thing that means that. | |
| 400 | No claim in claims[] carried usable text, or minSeverity was not one of high, medium, low. The body is { error } with no code field. An unrecognised minSeverity is refused rather than defaulted, because silently returning the unfiltered list looks like a filtered one. | |
| 500 | The check itself failed. |
curl -sS "$BASE/claim-validation/antecedent-basis" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"claims":[{"number":1,"text":"A device comprising a housing."},
{"number":2,"text":"The device of claim 1, wherein the lid is hinged."}]}'{
"available": true,
"source": "request",
"claims": [
{
"number": 2,
"isIndependent": false,
"dependsOn": [1],
"introducedTerms": [],
"issues": [
{
"claimNumber": 2,
"term": "lid",
"display": "the lid",
"type": "no-antecedent-basis",
"severity": "high",
"start": 34,
"end": 41,
"snippet": "The device of claim 1, wherein the lid is hinged."
}
]
}
],
"stats": {
"claimCount": 2,
"independentCount": 1,
"issueCount": 1,
"claimsWithIssues": 1,
"bySeverity": { "high": 1, "medium": 0, "low": 0 },
"byType": { "no-antecedent-basis": 1 }
}
}Check the filed claims of an application
The same check as POST /antecedent-basis, run over the claims already on file for an application rather than over claims you supply.
An application whose claims are not in the warehouse answers 200 with { available: false, reason: "no-claims" }, not 404. The distinction is deliberate: the application exists and the request was well formed, we just have nothing to check. Branch on available before reading issues.
Path parameters
| Name | Type | Description |
|---|---|---|
| appNum req | string, ^\d{7,8}$ | US application number, digits only. |
Query parameters
| Name | Type | Description |
|---|---|---|
| minSeverity | string, one of high, medium, low | Lowest severity to report. Defaults to low. |
| includeSuppressed | boolean | Send 1 to include suppressed candidates with the rule that removed each. |
Responses
| 200 | { appNum, available: true, source: "warehouse", issues[], claims[], dependencies[], stats }, shaped exactly as the POST above, or { appNum, available: false, reason: "no-claims" } when nothing is on file. | |
| 400 | appNum is not a 7-8 digit US application number, or minSeverity was not one of high, medium, low. | |
| 502 | The claim pull from the warehouse failed. |
curl -sS "$BASE/claim-validation/antecedent-basis/16123456?minSeverity=high" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Map claim terms to their specification support
Map every claim term to the specification passages that give it meaning, with exact locations: section, paragraph number, and character offsets.
Each term is graded by how the spec supports it, not merely whether the word appears. A term can be formally defined, defined by the claim itself, scoped by enumeration, mapped to an embodiment, characterized functionally, merely described, or UNDESCRIBED. That last grade is the §112(a) written-description signal worth acting on.
claims[] is always required on this endpoint. Use GET /support/:appNum when you want the filed claims analyzed instead of your own.
Supply sections and the analysis runs against your own specification text and touches no network, which is what makes this usable on an unfiled draft. Supply appNum without sections and the filed specification is pulled for you. Supplying appNum with includeParents walks the continuity chain and checks each parent specification too, so a term supported here but in no ancestor is surfaced as new matter that cannot claim the parent's filing date. The walk needs appNum; it cannot run on text alone.
Body
| Name | Type | Description |
|---|---|---|
| claims req | object[], max 300 | Claim set to analyze, each { number?, text }. Always required here; GET /support/:appNum uses the filed claims instead. |
| sections | object[], max 60 | Specification sections to ground against, each { type?, name?, text }. Either this or appNum is required. |
| appNum | string, ^\d{7,8}$ | US application number. Required for the continuity walk, and used to pull the spec when sections is omitted. |
| includeParents | boolean | Walk the continuity chain and check each parent specification. Ignored without appNum. Defaults to false. |
| maxAncestors | integer, 0–12 | Cap on ancestors to check. Defaults to 6. |
| ocr | boolean | Allow OCR for image-only filings. Most provisionals are image-only, so the walk usually needs this to read them. Defaults to false. |
Responses
| 200 | Per-term support grades with locations, plus the ancestor results when the continuity walk ran. | |
| 400 | claims[] was empty, or neither sections[] nor appNum was supplied. | |
| 500 | The analysis failed. |
curl -sS "$BASE/claim-validation/support" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"appNum":"16123456","includeParents":true,"ocr":true,
"claims":[{"number":1,"text":"A battery pack comprising a phase-change layer."}]}'This one spends real model inference on each call. Run it in the sandbox →
Support map for a filed application and its parents
The support map for an application already on file, using its filed claims and its filed specification. No claim text is supplied by the caller.
The continuity walk runs by default here, which is the opposite of POST /support. Send parents=0 to analyze the application's own specification alone. The walk is what makes this call slow and what makes it worth making: it is where new matter shows up.
OCR is opt-in with ocr=1 and is usually needed for the walk to be meaningful, because most provisionals are image-only scans with no extractable text layer. Without it an unreadable ancestor contributes nothing, and a term it actually supports can be reported as new matter. The flag is also killable server-side: when SPEC_OCR_DISABLED is set, ocr=1 is ignored rather than refused.
Path parameters
| Name | Type | Description |
|---|---|---|
| appNum req | string, ^\d{7,8}$ | US application number, digits only. |
Query parameters
| Name | Type | Description |
|---|---|---|
| parents | boolean | Send 0 to skip the continuity walk. Defaults to 1. |
| maxAncestors | integer, 0–12 | Cap on ancestors to check. Defaults to 6. |
| ocr | boolean | Send 1 to allow OCR on image-only filings. |
Responses
| 200 | Per-term support grades with locations, plus per-ancestor results and any new-matter findings when the continuity walk ran. | |
| 400 | appNum is not a 7-8 digit US application number. | |
| 502 | The specification pull or the analysis failed. |
curl -sS "$BASE/claim-validation/support/16123456?ocr=1&maxAncestors=4" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"Warm-up
Start the inference hub before a search needs it, so the cold start is paid off the critical path.
Start the inference hub ahead of a search
Start the inference hub before you need it.
The hub scales to zero, so the first search after an idle period pays ~75s of model loading. Call this a minute or two ahead and that cost is paid off the critical path; the search that follows runs at its warm latency of a few seconds.
Scaling to zero is a tier decision, not an accident: a held instance is provisioned for contracted tiers and not for the evaluation tier. warm_policy in the response says which the caller is on, whether an instance is held for it right now, and what to do.
The call returns immediately whether or not the hub is ready — it never blocks for the cold start. Poll GET /warmup to watch it become ready, or simply proceed and accept whatever state the hub is in.
Query parameters
| Name | Type | Description |
|---|---|---|
| rerank | boolean | Also load the reranker, which search_prior_art needs when useReranking is set. Adds ~25s to the warm-up and is unnecessary for retrieval alone. Defaults to false. |
| wait | integer | Seconds to wait for the models to finish loading before answering, up to 120. The default of 0 returns straight away and leaves the caller to poll. Set this and the call blocks until ready is true or the wait runs out, which is one round trip instead of a polling loop. Defaults to 0. |
Responses
| 200 | { ready, warming, models, estimatedReadySeconds, warmWindowSeconds, warm_policy, questions_needing_encoder }. ready true means a warm instance exists now; it is not a reservation. warm_policy carries tier, held_warm (whether an instance is held for that tier on this deployment) and why, the sentence to act on. encoder says which encoder serves the next search: hub, gpu (the index v2 encoder, which scales to zero), or vm when the always-on query encoder takes it, which is ready at once. | |
| 502 | UPSTREAM_ERROR | The inference hub could not be reached at all. |
curl -sS -X POST "$BASE/warmup?rerank=true" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"ready": false,
"warming": true,
"models": { "encoder": false, "reranker": false },
"estimatedReadySeconds": 100,
"warmWindowSeconds": 900,
"note": "Cloud Run routes each request independently, so a warm instance makes a fast search likely rather than guaranteed."
}Whether the inference hub is warm
Whether the inference hub is warm right now.
Read-only: it reports state and starts nothing. Use it to poll after POST /warmup, or to decide whether a search is about to be fast before committing to it.
Responses
| 200 | { ready, models, warmWindowSeconds, warm_policy, questions_needing_encoder }. ready reflects the encoder only; check models.reranker if the next call sets useReranking. | |
| 502 | UPSTREAM_ERROR | The inference hub could not be reached at all. |
curl -sS "$BASE/warmup" -H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"ready": true,
"models": { "encoder": true, "reranker": false },
"warmWindowSeconds": 900
}Usage
What the calling key has spent and has left this month and today, and when each limit resets. Free, and never counted.
What this key has spent and has left, and when each limit resets
The calling key's plan, what it has spent this month and today, and what is left.
Every figure is the holder's: for a key in an organisation, the organisation's shared pool (pooled is true and org names it), which is what the quota is enforced against. Otherwise the key's own.
credits.monthly is the allowance: used, remaining and resetAt. credits.purchased is bought credits, spent after the allowance and never expiring. credits.spendable is the two together, which is what the next call can spend before anything past the allowance is touched. credits.overage is what was served this month past both; it is forgiven when the month resets. A paid plan carries softCeiling: it keeps serving to twice its allowance, and remaining is what is left of that headroom. The evaluation tier carries dailyFloor instead: once the month is spent it still serves credits a day. While it is not in force (active: false) it says only when it applies; once active it adds usedToday, remainingToday and resetAt. A plan with neither stops at the allowance.
requests.day and requests.month are the request ceilings, which count every call except warm-up, this one and MCP protocol messages. key.expiresAt is when the key stops working if nobody signs in: an account key renews on every sign-in at antecedint.com and whenever an application reconnects. All times are ISO 8601 in UTC.
Pass credits to ask about a planned spend: projected then says whether calls totalling that would be served and how they would be drawn.
Query parameters
| Name | Type | Description |
|---|---|---|
| credits | integer, 1–1000000 | A planned spend. Adds projected: whether it would be served, and how much would come from the allowance, the purchased balance and overage. |
Responses
| 200 | { tier, plan, pooled, org, credits, requests, key, upgrade, account, timestamp }, plus projected when credits is passed. | |
| 400 | VALIDATION_ERROR | credits is not a positive integer. |
| 503 | USAGE_UNAVAILABLE | The deployment's key store keeps no usage counters. |
curl -sS "$BASE/usage" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"tier": "free",
"plan": "Evaluate",
"pooled": false,
"org": null,
"credits": {
"monthly": { "allowance": 500, "used": 20, "remaining": 480, "resetAt": "2026-10-01T00:00:00.000Z" },
"purchased": { "balance": 0 },
"spendable": 480,
"overage": { "used": 0, "active": false },
"softCeiling": null,
"dailyFloor": { "credits": 20, "active": false, "appliesWhen": "the monthly allowance and purchased credits are both spent" }
},
"requests": {
"day": { "used": 2, "limit": 100, "remaining": 98, "resetAt": "2026-09-28T00:00:00.000Z" },
"month": { "used": 2, "limit": 2000, "remaining": 1998, "resetAt": "2026-10-01T00:00:00.000Z" }
},
"key": { "keyId": "ak_live_1a2b3c4d", "status": "active", "expiresAt": "2026-12-26T09:14:00.000Z", "renewsOnSignIn": true },
"upgrade": "https://antecedint.com/pricing",
"account": "https://antecedint.com/account"
}Background jobs
The status and result of a tool call made with async true. Free, and never counted.
Read a background job's status and result
One job's status, and the tool's result once it has finished.
status is queued, running, succeeded or failed. A finished job carries result, the payload the tool returned (the same JSON a direct call returns), and is_error, which is true when the tool itself reported an error. A job whose result could not be kept carries error_code instead (RESULT_TOO_LARGE: call the tool without async).
Pass wait_seconds (up to 25) to hold the request until the job finishes or the wait runs out: one call instead of a polling loop. Jobs are kept for a day after they are created. A handle that belongs to another key reads as no job at all.
Body
| Name | Type | Description |
|---|---|---|
| job_id req | string, 20–80 chars | The handle an async tool call returned, job_<id>.<key>. |
| wait_seconds | integer, 0–25 | Wait up to this long for the job to finish. Defaults to 0. |
| page | integer, 1–1000 | Which page of a long result to return. Defaults to 1. |
Responses
| 200 | { job_id, tool, status, created, started?, finished?, run_ms?, is_error?, result?, pagination?, context?, error_code?, next? }. A result longer than one page (about 24,000 characters of JSON) is split on its longest list; pagination gives { page, pages, field, items, next }. | |
| 400 | VALIDATION_ERROR | job_id is missing or wait_seconds is out of range. |
| 400 | INVALID_JOB_ID | job_id is not a whole job handle. |
| 404 | NOT_FOUND | No such job for this key, or it has expired. |
curl -sS -X POST "$BASE/jobs/read" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"job_id":"job_Q2F0cy1hbmQtZG9ncw.<key>","wait_seconds":20}'{
"job_id": "job_Q2F0cy1hbmQtZG9ncw.<key>",
"tool": "search_prior_art",
"status": "succeeded",
"created": "2026-09-27T18:40:02.114Z",
"started": "2026-09-27T18:40:02.310Z",
"finished": "2026-09-27T18:40:19.842Z",
"run_ms": 17532,
"is_error": false,
"result": { "success": true, "data": { "specifications": [] } }
}List this key's recent background jobs
The calling key's recent jobs, newest first: tool, status and times only. A result is read with the full handle the async call returned, which is not stored, so this cannot return results or handles.
Query parameters
| Name | Type | Description |
|---|---|---|
| limit | integer, 1–100 | How many to return. Defaults to 20. |
Responses
| 200 | { count, jobs: [{ id, tool, status, created, finished? }], note } | |
| 400 | VALIDATION_ERROR | limit is out of range. |
curl -sS "$BASE/jobs?limit=5" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"count": 1,
"jobs": [{ "id": "job_Q2F0cy1hbmQtZG9ncw", "tool": "test_claim_support", "status": "running", "created": "2026-09-27T18:41:00.000Z" }],
"note": "Results are read with the full job_id the async call returned; it is not stored and cannot be listed."
}The map
The areas of law this server covers and the ones planned, as data: what the MCP front door lists first.
List the areas of law
The areas of law this server covers and the ones planned, each live area with its corpora and how many gardens, paths and capabilities it holds on this deployment.
Query parameters
| Name | Type | Description |
|---|---|---|
| area | string, 1–40 chars | One area id, such as ip, to list only that area. |
Responses
| 200 | { areas: [{ id, title, status, corpora, gardens, paths, capabilities }], planned, timestamp } |
curl -sS "$BASE/areas" -H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"areas": [{ "id": "ip", "title": "Patents and IP", "status": "live", "corpora": ["patents", "prosecution", "guidance"], "gardens": 11, "paths": 1, "capabilities": 44 }],
"planned": [{ "key": "caselaw", "label": "Case law", "phase": "Phase 2" }],
"timestamp": "2026-09-28T12:00:00.000Z"
}List the capabilities in an area, garden or path
The capabilities inside an area, a garden or a path, one line each: id, what it does, price, whether it writes, and its arguments in short form. run_with names the front-door tool that runs it: run_tool for one that reads, update_workspace for one that saves or changes something.
Query parameters
| Name | Type | Description |
|---|---|---|
| area | string, 1–40 chars | An area id, such as ip. |
| garden | string, 1–60 chars | A garden id, such as ip.records. |
| path | string, 1–60 chars | A path id, such as ip.provisional. |
| query | string, 1–200 chars | Words to match in ids, titles and descriptions. |
Responses
| 200 | { count, tools: [{ id, title, summary, area, garden, path, writes, run_with, credits, args }], timestamp } | |
| 400 | VALIDATION_ERROR | A filter is empty or too long. |
curl -sS "$BASE/capabilities?garden=ip.prior-art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"count": 1,
"tools": [{ "id": "search_prior_art", "title": "Prior Art Search", "summary": "Semantic prior-art search over 10.5M+ US patents for a claim and/or abstract.", "area": "ip", "garden": "ip.prior-art", "path": null, "writes": false, "run_with": "run_tool", "credits": 10, "args": { "claims": "string", "abstract": "string" } }],
"timestamp": "2026-09-28T12:00:00.000Z"
}Describe one capability
One capability in full: its description, complete argument schema, an example that runs, the fields its answer carries, the limits it states, its price, whether it can run in the background, and which front-door tool runs it.
Path parameters
| Name | Type | Description |
|---|---|---|
| id req | string, ^[a-z][a-z0-9_]{1,63}$ | The capability id, such as search_prior_art. |
Responses
| 200 | { id, title, summary, description, area, garden, path, writes, run_with, credits, args, inputSchema, example, returns, context, async, preconditions, timestamp }. preconditions lists the calls to make first on this key's tier, as { tier, when, call, args, why }; empty when none apply. | |
| 400 | VALIDATION_ERROR | The id is not a capability id. |
| 404 | NOT_FOUND | No capability with that id on this deployment. |
curl -sS "$BASE/capabilities/search_prior_art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"id": "search_prior_art",
"title": "Prior Art Search",
"run_with": "run_tool",
"credits": 10,
"inputSchema": { "type": "object", "properties": { "claims": { "type": "string" } } },
"example": { "claims": "A method comprising …" },
"async": true,
"timestamp": "2026-09-28T12:00:00.000Z"
}The map
The capabilities inside each area, garden and path, as data: what the MCP front door lists and describes.
List the areas of law
The areas of law this server covers and the ones planned, each live area with its corpora and how many gardens, paths and capabilities it holds on this deployment.
Query parameters
| Name | Type | Description |
|---|---|---|
| area | string, 1–40 chars | One area id, such as ip, to list only that area. |
Responses
| 200 | { areas: [{ id, title, status, corpora, gardens, paths, capabilities }], planned, timestamp } |
curl -sS "$BASE/areas" -H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"areas": [{ "id": "ip", "title": "Patents and IP", "status": "live", "corpora": ["patents", "prosecution", "guidance"], "gardens": 11, "paths": 1, "capabilities": 44 }],
"planned": [{ "key": "caselaw", "label": "Case law", "phase": "Phase 2" }],
"timestamp": "2026-09-28T12:00:00.000Z"
}List the capabilities in an area, garden or path
The capabilities inside an area, a garden or a path, one line each: id, what it does, price, whether it writes, and its arguments in short form. run_with names the front-door tool that runs it: run_tool for one that reads, update_workspace for one that saves or changes something.
Query parameters
| Name | Type | Description |
|---|---|---|
| area | string, 1–40 chars | An area id, such as ip. |
| garden | string, 1–60 chars | A garden id, such as ip.records. |
| path | string, 1–60 chars | A path id, such as ip.provisional. |
| query | string, 1–200 chars | Words to match in ids, titles and descriptions. |
Responses
| 200 | { count, tools: [{ id, title, summary, area, garden, path, writes, run_with, credits, args }], timestamp } | |
| 400 | VALIDATION_ERROR | A filter is empty or too long. |
curl -sS "$BASE/capabilities?garden=ip.prior-art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"count": 1,
"tools": [{ "id": "search_prior_art", "title": "Prior Art Search", "summary": "Semantic prior-art search over 10.5M+ US patents for a claim and/or abstract.", "area": "ip", "garden": "ip.prior-art", "path": null, "writes": false, "run_with": "run_tool", "credits": 10, "args": { "claims": "string", "abstract": "string" } }],
"timestamp": "2026-09-28T12:00:00.000Z"
}Describe one capability
One capability in full: its description, complete argument schema, an example that runs, the fields its answer carries, the limits it states, its price, whether it can run in the background, and which front-door tool runs it.
Path parameters
| Name | Type | Description |
|---|---|---|
| id req | string, ^[a-z][a-z0-9_]{1,63}$ | The capability id, such as search_prior_art. |
Responses
| 200 | { id, title, summary, description, area, garden, path, writes, run_with, credits, args, inputSchema, example, returns, context, async, preconditions, timestamp }. preconditions lists the calls to make first on this key's tier, as { tier, when, call, args, why }; empty when none apply. | |
| 400 | VALIDATION_ERROR | The id is not a capability id. |
| 404 | NOT_FOUND | No capability with that id on this deployment. |
curl -sS "$BASE/capabilities/search_prior_art" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"id": "search_prior_art",
"title": "Prior Art Search",
"run_with": "run_tool",
"credits": 10,
"inputSchema": { "type": "object", "properties": { "claims": { "type": "string" } } },
"example": { "claims": "A method comprising …" },
"async": true,
"timestamp": "2026-09-28T12:00:00.000Z"
}Status
This key's usage and the search models' warmth in one answer, with an optional warm-up. Free, and never counted.
Usage and model warmth for this key
What this key has spent and has left, and whether the search models are warm. Starts nothing.
usage is the body GET /usage returns (plan, credits, requests, key, and projected when credits is passed). models is the body GET /warmup returns.
Query parameters
| Name | Type | Description |
|---|---|---|
| credits | integer, 1–1000000 | A planned spend; adds usage.projected. |
Responses
| 200 | { usage, models, timestamp } | |
| 400 | VALIDATION_ERROR | credits is not a positive integer. |
| 502 | UPSTREAM_ERROR | The inference hub could not be reached at all. |
curl -sS "$BASE/status" -H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"usage": { "tier": "free", "credits": { "monthly": { "allowance": 500, "used": 20, "remaining": 480 } } },
"models": { "ready": false, "models": { "encoder": false, "reranker": false }, "warmWindowSeconds": 900 },
"timestamp": "2026-09-28T12:00:00.000Z"
}Start the search models, then report usage and warmth
The same answer, after starting the search models if they are cold. Returns at once unless wait is set, which blocks up to that many seconds until the models are ready.
Query parameters
| Name | Type | Description |
|---|---|---|
| warm | boolean | Start the models (the get_status tool sends it with warm). Defaults to true. |
| rerank | boolean | Also load the reranker (about 25 seconds more). Defaults to false. |
| wait | integer, 0–120 | Seconds to wait for the models to be ready. Defaults to 0. |
| credits | integer, 1–1000000 | A planned spend; adds usage.projected. |
Responses
| 200 | { usage, models, timestamp }, models as POST /warmup returns it. Where case law is served, the call also starts the case-law search and the citation web, and models.caselaw_search says whether the search is loaded (ready) or starting from zero instances (starting, with estimatedReadySeconds). | |
| 400 | VALIDATION_ERROR | A parameter is out of range. |
| 502 | UPSTREAM_ERROR | The inference hub could not be reached at all. |
curl -sS -X POST "$BASE/status?wait=60" -H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"usage": { "tier": "free" },
"models": { "ready": true, "warming": false, "models": { "encoder": true, "reranker": false } },
"timestamp": "2026-09-28T12:00:00.000Z"
}Reference
Dated reference material: fee schedules, filing steps, drafting rules and the registry. The same set MCP resources serve.
List the dated reference material
The references this deployment serves, optionally narrowed to those whose title, description or uri contains every word of query.
Query parameters
| Name | Type | Description |
|---|---|---|
| query | string, 1–200 chars | Words to match against each reference's title, description and uri. |
Responses
| 200 | { count, references: [{ uri, name, title, description, area }], timestamp } | |
| 400 | VALIDATION_ERROR | query is empty or too long. |
curl -sS "$BASE/references?query=fee" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"count": 1,
"references": [{ "uri": "antecedint://ip/uspto/fee-schedule", "name": "uspto-fee-schedule", "title": "USPTO provisional fees", "description": "The provisional filing fee …", "area": "ip" }],
"timestamp": "2026-09-27T19:00:00.000Z"
}Read one reference by uri
One reference's content, by uri. JSON references are returned parsed under content; others as text.
Query parameters
| Name | Type | Description |
|---|---|---|
| uri req | string, 12–200 chars | The reference's uri, antecedint://<area>/<topic>/<name>. |
Responses
| 200 | { uri, mimeType, content | text, timestamp } | |
| 400 | VALIDATION_ERROR | uri is missing. |
| 404 | REFERENCE_NOT_FOUND | No reference at that uri on this deployment. |
curl -sS "$BASE/references/read?uri=antecedint://service/jobs" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"uri": "antecedint://service/jobs",
"mimeType": "text/markdown",
"text": "# Background jobs\n\nPass `async: true` to any tool that lists it. …",
"timestamp": "2026-09-27T19:00:00.000Z"
}Prosecution intelligence
CPC scheme and empirical routing, art-unit behaviour, and examiner statistics.
CPC symbol with its art-unit distribution and children
One CPC symbol, resolved three ways at once: what the scheme says it means, which art units actually examine it, and what sits under it.
The art-unit distribution is empirical rather than declared — it is where applications carrying this symbol were really routed, with the modal unit, the per-unit probabilities and the Shannon entropy of the spread. A low entropy means the symbol predicts the art unit; a high one means it does not, which is the more useful answer when deciding whether to argue classification.
children is capped by childLimit, because a subclass can carry thousands of subgroups and a caller asking about C11D wants to know that it has children, not to receive all of them. child_count always reports the true total. The art-unit distribution is capped the same way by distributionLimit: it is sorted by count, unique_art_units is the true total, and a symbol examined by 222 units does not need all 222 listed to show that one of them takes 37%.
Path parameters
| Name | Type | Description |
|---|---|---|
| code req | string, ^[A-HY][0-9A-Z/]{0,18}$ | CPC symbol, e.g. C11D or C11D7/261. |
Query parameters
| Name | Type | Description |
|---|---|---|
| childLimit | integer, 0–500 | How many child symbols to return. Defaults to 50. |
| distributionLimit | integer, 0–500 | How many art units to list in art_units.distribution, largest first. Defaults to 20. |
Responses
| 200 | { code, scheme, art_units, children[], child_count }. scheme is null for a symbol with routing data but no scheme entry; art_units is null for a symbol nothing has been routed under. | |
| 400 | VALIDATION_ERROR | code is not a CPC symbol, or a limit is outside 0-500. |
| 404 | NOT_FOUND | Neither the scheme nor the routing data knows this symbol. |
| 503 | CORPUS_UNAVAILABLE | The corpus database is not configured or not reachable. |
curl -sS "$BASE/patent-intel/cpc/C11D?childLimit=5" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"code": "C11D",
"scheme": {
"code": "C11D",
"title": "DETERGENT COMPOSITIONS",
"level": "subclass",
"parent": "C11"
},
"art_units": {
"level": "subclass",
"total_count": 14476,
"unique_art_units": 222,
"top_art_unit": "1761",
"top_art_unit_probability": 0.3689,
"entropy": 4.3798,
"distribution": [
{ "au": "1761", "count": 5227, "probability": 0.36893 }
]
},
"children": [
{ "code": "C11D1/00", "title": "Detergent compositions", "level": "group" }
],
"child_count": 132
}CPC classification for a publication or application number
The CPC assignment on one published application or granted patent, as the USPTO Master Classification File records it.
The number is tried as a publication number first and an application number second, so a caller holding either can ask without saying which it has. The main symbol is resolved against the scheme, so the answer carries a title and not only a code.
inventive_cpcs are the symbols covering what is claimed; additional_cpcs cover subject matter disclosed but not claimed. Callers building a search from this usually want the inventive set alone.
Path parameters
| Name | Type | Description |
|---|---|---|
| number req | string, ^\d{7,12}$ | Publication or US application number, digits only. |
Responses
| 200 | { publication_number, application_number, main_cpc, main_cpc_title, inventive_cpcs[], additional_cpcs[], ... }. | |
| 400 | VALIDATION_ERROR | number is not 7-12 digits. |
| 404 | NOT_FOUND | No classification record for this number. |
| 503 | CORPUS_UNAVAILABLE | The corpus database is not configured or not reachable. |
curl -sS "$BASE/patent-intel/classification/20010000001" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"publication_number": "20010000001",
"application_number": "09725796",
"kind_code": "A1",
"main_cpc": "C11D7/261",
"main_cpc_title": "Organic compounds containing oxygen",
"inventive_cpcs": ["C11D7/261", "C11D7/24"],
"additional_cpcs": ["C11D7/267", "C11D7/28"]
}Art-unit profile, statistics and examiner roster
One art unit: what it examines and how it behaves.
Assembled from the four collections that describe a unit — the statistics, the descriptive record, the generated enrichment and the examiner roster — so a caller makes one request rather than four.
statistics carries allowance and rejection behaviour, timing, interview receptiveness, RCE tolerance and estimated cost, averaged across the unit's examiners. Read statistics.data_quality before relying on any of it: it reports how many applications and office actions the averages rest on, and the volume, recency and completeness scores behind them. Units with thin data carry the same field names and much weaker numbers.
The roster's application numbers are not returned. One unit carries tens of thousands of them, which is most of a 209 KB document and no use in a profile. The model-written description is not returned whole either: on 1725 it was 9,887 characters, 56% of the response, and it filed "bibs for hairdressers' rooms" under a materials unit. generated_context says the same in a paragraph, so description is served as its opening and its length.
examiner_count is the length of the roster served. Where the stored statistics counted a different roster (1725 lists 28 examiners against a stored 27), the stored figure appears as examiner_count_in_statistics so the disagreement is visible rather than resolved silently.
Path parameters
| Name | Type | Description |
|---|---|---|
| artUnit req | string, ^\d{3,4}$ | USPTO art unit, e.g. 2872. |
Responses
| 200 | { art_unit, technology_center, title, generated_context, description, keywords[], cpc_codes, examiners[], examiner_count, statistics }. cpc_codes summarises rather than lists: a total, counts by CPC section, and the 25 commonest subclasses. The raw list runs to 24,135 symbols for a single unit and two unrelated units share 57% of it, so it described the corpus more than the unit and made this response 383 KB. statistics is null for a unit that has a descriptive record but no computed statistics; inside it, claims_analysis.independentClaimsStats.avgIndependentClaims is null with a note where the stored value tracked the total claim count. | |
| 400 | VALIDATION_ERROR | artUnit is not 3-4 digits. |
| 404 | NOT_FOUND | No collection holds this art unit. |
| 503 | CORPUS_UNAVAILABLE | The corpus database is not configured or not reachable. |
curl -sS "$BASE/patent-intel/art-unit/2872" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"art_unit": "2872",
"technology_center": "2800",
"title": "Optics: Measuring and Testing",
"examiner_count": 63,
"cpc_codes": ["G01B", "G02B"],
"examiners": ["GREY CHRISTOPHER P", "YOUNG HUGH P"],
"statistics": {
"portfolio": { "total_ctnf_issued_avg": 902.86 },
"interview_metrics": { "interview_success_rate": 65.89 },
"data_quality": {
"total_applications_analyzed": 53392,
"office_actions_analyzed": 132188,
"completeness_score": 5.54
}
}
}Search examiners by name or art unit
Find examiners by surname or art unit.
Matching is anchored: an exact surname, or a prefix of the full name in the USPTO's surname-first form. An unanchored substring search would be a regex over 10,308 documents averaging a megabyte each, which is a collection scan reading 11 GB to answer a lookup. Callers wanting a specific examiner should pass the surname and filter the result.
Query parameters
| Name | Type | Description |
|---|---|---|
| name | string, 2–80 chars | Surname, or a prefix of the surname-first full name. |
| artUnit | string, ^\d{3,4}$ | Restrict to one art unit. |
| limit | integer, 1–100 | Maximum matches to return. Defaults to 20. |
Responses
| 200 | { count, examiners[] }, each { examiner_id, full_name, art_unit, technology_center }. Empty when neither name nor artUnit is given. | |
| 400 | VALIDATION_ERROR | A parameter failed validation. |
| 503 | CORPUS_UNAVAILABLE | The corpus database is not configured or not reachable. |
curl -sS "$BASE/patent-intel/examiners?name=SMITH&artUnit=1609" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"count": 1,
"examiners": [
{
"examiner_id": "68a73eaad7496de7109778b7",
"full_name": "SMITH ADAM M",
"art_unit": "1609",
"technology_center": "Technology Center 1600"
}
]
}Examiner statistics and behavioural profile
One examiner's statistics, by examiner id or by USPTO surname-first name.
Both forms are accepted because a caller reading an office action has the name and a caller following an art-unit roster has the id.
The response carries rejection analytics, portfolio counts, interview and RCE behaviour, timing, cost analysis and percentile rankings against the unit and the corps, plus claim_interpretation where a model-written read of how this examiner construes claims exists — it does for 11 examiners, and is null for the rest rather than absent.
Six sections are withheld by default and named in sections_available. Two are cold: behavioral_patterns and rejection_analysis hold per-application detail and are together 10.6 GB of the 11.1 GB collection, the largest single document being 14.2 MB. Four are hot but wide: applications_with_interviews and applications_with_rcex are per-application lists (hundreds of rows each), by_sequence_length and document_code_breakdown are histograms with hundreds of keys. Together they were 83% of a default response. Each is replaced by its count and the include name that brings it back; document_code_breakdown keeps its ten largest codes.
data_quality reports what the numbers rest on, and says what was withheld or relabelled. populations names the five denominators that appear in one response (all applications, analysed, with documents, with office actions, with a filing date). volume.tier replaces an upstream score that was 5 for every examiner. withheld[] lists fields removed because their values were wrong and not recoverable, with what was observed; notes[] lists sections served as null because they were never computed (percentile_rankings, claims_analysis on every examiner sampled), and pairs of fields that disagree.
Path parameters
| Name | Type | Description |
|---|---|---|
| examiner req | string, 2–120 chars | Examiner id, or USPTO surname-first full name. |
Query parameters
| Name | Type | Description |
|---|---|---|
| include | string | Comma-separated sections to add: behavioral_patterns, rejection_analysis (cold; megabytes), applications_with_interviews, applications_with_rcex, by_sequence_length, document_code_breakdown (hot; thousands of tokens). Unknown names are ignored. |
Responses
| 200 | { examiner_id, full_name, art_unit, technology_center, portfolio, rejection_analytics, interview_metrics, rcex_metrics, timeline_metrics, strategic_insights, data_quality, claim_interpretation, sections_available[], sections_included[], ... }. percentile_rankings and claims_analysis are null where never computed. | |
| 400 | VALIDATION_ERROR | examiner is shorter than 2 characters or longer than 120. |
| 404 | NOT_FOUND | No examiner with this id or name. |
| 503 | CORPUS_UNAVAILABLE | The corpus database is not configured or not reachable. |
curl -sS "$BASE/patent-intel/examiner/SMITH%20ADAM%20M" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"examiner_id": "68a883c3d8cb3a33568ff86d",
"full_name": "HASAN MOHAMMED A",
"art_unit": "2872",
"technology_center": "2800",
"portfolio": { "total_office_actions_issued": 6280 },
"percentile_rankings": null,
"data_quality": {
"total_applications_analyzed": 2711,
"office_actions_analyzed": 6280,
"populations": { "total_applications": 2711, "analysed": 2711, "with_documents": 2707, "with_office_actions": 2605, "with_filing_date": 2490, "three_year_cohort": 187 },
"volume": { "applications_analyzed": 2711, "tier": "large" },
"notes": ["percentile_rankings: not computed for this examiner (all three ranking tables were empty upstream)."]
},
"claim_interpretation": null,
"sections_available": ["behavioral_patterns", "rejection_analysis", "applications_with_interviews", "applications_with_rcex", "by_sequence_length", "document_code_breakdown"],
"sections_included": []
}Examination guidance
The MPEP and the EPO Guidelines, the graph of how their sections cite each other, and the form paragraphs the USPTO pastes into office actions.
One MPEP section with its rules and required examiner actions
One MPEP section, as an examiner is required to apply it.
Beyond the section text, each record carries keyRules and examinerActions: what the section obliges, separated from the prose that obliges it. That is usually what a caller holding a rejection actually wants, since the argument is about whether the examiner did what the section required.
Section ids carry dots and parentheses and the punctuation is part of the key, so 601.01(c) is passed through exactly as written.
Path parameters
| Name | Type | Description |
|---|---|---|
| sectionId req | string, ^[0-9A-Za-z.()\-]{1,40}$ | MPEP section id, e.g. 2106 or 601.01(c). Dots and parentheses are part of the id. |
Responses
| 200 | The section, with content, keyRules, examinerActions, legalReferences, technologyDomains and enrichedSummary. | |
| 400 | VALIDATION_ERROR | sectionId is not a well-formed MPEP section id. |
| 404 | NOT_FOUND | No MPEP section carries that id. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/mpep/2106" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"sectionId": "2106",
"title": "Patent Subject Matter Eligibility",
"chapter": "2100",
"topicCategory": "patentability",
"keyRules": ["elided"],
"examinerActions": ["elided"],
"legalReferences": ["35 U.S.C. 101"]
}One EPO Guidelines section with its rules and citations
One section of the EPO Guidelines for Examination.
Deliberately the same shape as the MPEP route, because the flow that reaches it is the same flow one step later: an applicant with a US rejection usually has a European family member, and an agent that learned one lookup should not have to learn a second.
These records were merged from two source collections that each held half of each section, so a complete document carries both the generated half (keyRules, examinerActions) and the source half (citations, sourceUrl, parentSection, childSections).
Path parameters
| Name | Type | Description |
|---|---|---|
| sectionId req | string, ^[0-9A-Za-z.,_ \-]{1,40}$ | EPO Guidelines section id in any of its written forms: g-ii-3.3, G-II, 3.3, or the graph's epo-g-ii-3-3. All resolve to the same section. |
Responses
| 200 | The section, with content, keyRules, examinerActions, citations, parentSection, childSections and sourceUrl. | |
| 400 | VALIDATION_ERROR | sectionId is not a well-formed EPO section id. |
| 404 | NOT_FOUND | No EPO section carries that id. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/epo/g-ii-3.3" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"sectionId": "epo-g-ii-3-3",
"title": "Mathematical methods",
"part": "G",
"chapter": "II",
"keyRules": ["elided"],
"citations": ["elided"],
"sourceUrl": "https://www.epo.org/en/legal/guidelines-epc"
}One office-action form paragraph, with its statute and MPEP section
The literal paragraph an examiner pasted into an office action.
This is the sharpest thing in the dataset. A caller holding a rejection has a paragraph number and nothing else, and this turns it into the statute behind it, the MPEP section it rests on, the rejection type it belongs to, and the notes the examiner was given about when to use it. brackets lists the placeholders the examiner had to fill, which is often where the substance of a rejection actually sits.
isAIA and preAIAEquivalent matter for anything filed near the changeover: citing the wrong one is citing law that does not apply to the application.
The paragraph symbol is stripped, so a code copied straight out of a PDF as ¶ 6.11 resolves rather than returning a 404 that reads as "no such paragraph".
Path parameters
| Name | Type | Description |
|---|---|---|
| code req | string, ^[¶\s0-9A-Za-z.\-]{1,24}$ | Form paragraph code, e.g. 6.11 or 7.37.01. A leading ¶ is accepted and ignored. |
Responses
| 200 | The paragraph: title (its heading), template (the text as pasted, placeholders as [1], [2]), brackets, statute, statuteShort, rejectionType, category, isAIA, preAIAEquivalent, mpepSection, examinerNotes, mustFollow (paragraphs that have to appear before this one) and relatedParagraphs. truncated_at_source: true means the stored text ends before the paragraph does; quote it as partial. statute and rejectionType are each null on a majority of rows, and on different rows. | |
| 400 | VALIDATION_ERROR | code is not a well-formed form paragraph code. |
| 404 | NOT_FOUND | No form paragraph carries that code. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/form-paragraph/7.34.10" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"code": "7.34.10",
"title": "Indefinite Claim Language: “Such As”",
"template": "Regarding claim [1], the phrase “such as” renders the claim indefinite because it is unclear whether the limitations following the phrase are part of the claimed invention. See MPEP § 2173.05(d).",
"statute": null,
"rejectionType": "indefiniteness",
"mpepSection": "2175",
"examinerNotes": "Examiner Note: This form paragraph must be preceded by form paragraph 7.34.01.",
"mustFollow": ["7.34.01"]
}Form paragraphs filtered by rejection type or MPEP section
Every form paragraph an examiner could have reached for.
Given a rejection type, this is the set the examiner chose from, which is what an agent needs to tell "they picked the narrow one" from "this was the only option". Filtering by mpepSection answers the reverse: which paragraphs rest on a section you are already arguing about.
At least one filter is required. An unfiltered call would page through everything to no purpose, so the caller has to say which axis they are on rather than receive the whole table by default.
rejectionType takes either of the two vocabularies the corpus holds. The stored label is a word (obviousness, indefiniteness, means_plus_function) and the stored statute is a citation (35 U.S.C. 103(a), 37 CFR 1.52); each is null on a majority of rows, and on different rows. A query on either is expanded to both, so 112(b) reaches the paragraphs labelled indefiniteness as well as the ones citing the statute, and indefiniteness reaches the same set. filter.matched shows the expansion.
Query parameters
| Name | Type | Description |
|---|---|---|
| rejectionType | string, ^[0-9A-Za-z.()_ \-]{1,40}$ | A statute (102, 103, 112(b), 101, 121, or a CFR rule such as 1.52) or a label (obviousness, anticipation, indefiniteness, enablement, written_description, means_plus_function, abstract_idea, double_patenting, restriction, allowance, drawing_objection). Required unless mpepSection is given. |
| mpepSection | string, ^[0-9A-Za-z.()\-]{1,40}$ | MPEP section the paragraph rests on, e.g. 706, 707, 2175. Required unless rejectionType is given. |
| limit | integer, 1–100 | How many paragraphs to return. Defaults to 25. |
Responses
| 200 | { results[], count, filter }. filter echoes what was applied and filter.matched what rejectionType expanded to; an unrecognised value returns zero with filter.note listing the vocabulary. | |
| 400 | VALIDATION_ERROR | Neither filter was supplied, or one was malformed. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/form-paragraphs?rejectionType=112(b)&limit=5" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"results": ["one form paragraph per entry; elided here"],
"count": 5,
"filter": {
"rejectionType": "112(b)",
"matched": { "rejectionType": ["indefiniteness"], "statute": "35 U.S.C. 112(b)" }
}
}One-hop cross-references into and out of a guidance section
What a guidance section points at, and what points at it.
One hop, both directions, because they answer different questions. Forward is what else this rule depends on. Backward is what breaks if you misread it, and it is the direction that is hard to get any other way.
Which graph is read off the node id rather than passed separately: ids are mpep-601.01(c) and epo-c-ix-3, so the prefix routes the query. An id with neither prefix is a 404 rather than a guess, because answering an EPO question with US law is worse than answering nothing.
A hub section is cited by hundreds of others, so the fan-out is capped and truncated says which direction hit the cap. A caller seeing exactly limit edges cannot otherwise tell a hub from a coincidence.
Path parameters
| Name | Type | Description |
|---|---|---|
| nodeId req | string, ^(mpep|epo)-[0-9A-Za-z.()\-]{1,40}$ | Graph node id. The prefix selects the corpus: mpep-2106, epo-c-ix-3. |
Query parameters
| Name | Type | Description |
|---|---|---|
| limit | integer, 1–200 | Maximum edges per direction. Defaults to 50. |
Responses
| 200 | { node, corpus, outgoing[], incoming[], truncated, limit }. Each edge is { source, target, weight, type, bidirectional }. | |
| 400 | VALIDATION_ERROR | nodeId carries no recognised prefix, or limit is outside 1-200. |
| 404 | NOT_FOUND | No graph node carries that id. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/graph/mpep-2106?limit=10" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"node": { "nodeId": "mpep-2106", "inDegree": 214, "outDegree": 63, "isHub": true },
"corpus": "mpep",
"outgoing": [{ "source": "mpep-2106", "target": "mpep-2106.04", "weight": 8, "type": "cites" }],
"incoming": [{ "source": "mpep-2103", "target": "mpep-2106", "weight": 5, "type": "cites" }],
"truncated": { "outgoing": false, "incoming": true },
"limit": 10
}One USPTO design search code
One USPTO design search code.
A classification scheme rather than guidance. It sits in this namespace because it travelled with the same passover, not because it belongs beside the MPEP, and it is documented that way rather than filed somewhere tidier that would imply a relationship these records do not have.
Path parameters
| Name | Type | Description |
|---|---|---|
| code req | string, ^[0-9]{2}(\.[0-9]{2}){0,3}$ | Design search code, e.g. 03.19.17. |
Responses
| 200 | The code, with descriptions[] (every phrasing the USPTO files it under), major and sub. | |
| 400 | VALIDATION_ERROR | code is not a design search code. |
| 404 | NOT_FOUND | No design code carries that value. |
| 503 | CORPUS_UNAVAILABLE | The guidance dataset is not configured or not reachable. |
curl -sS "$BASE/guidance/design-code/03.19.17" \
-H "Authorization: Bearer $ANTECEDINT_API_KEY"{
"code": "03.19.17",
"descriptions": ["Fish symbol used for religious significance", "Ichthys"],
"major": "03",
"sub": "03.19"
}Errors and quotas
Authentication and quota failures happen before a route runs, so they look the same whichever endpoint you called.
| Status | Code | Cause |
|---|---|---|
| 401 | MISSING_API_KEY | No Authorization header. |
| 401 | INVALID_AUTH_FORMAT | The header is not of the form "Bearer <key>". |
| 401 | KEY_NOT_FOUND | The key does not exist, is suspended, or is revoked. |
| 401 | API_KEY_EXPIRED | The key is past its expiry date. |
| 403 | IP_NOT_WHITELISTED | The key has an IP allowlist and the request came from outside it. |
| 429 | USAGE_LIMIT_EXCEEDED | Over the daily or monthly quota. The body reports the limit it enforced and when it resets. |
| 500 | AUTH_SYSTEM_ERROR | Key validation itself failed. Retry. |
| 503 | The instance is draining for a deploy. Retry. |
Quotas default to 1,000 requests a day and 30,000 a month, set per key when it is issued, and counted per key rather than per IP. Two services sharing a key share its budget.
One inconsistency worth knowing
Two envelopes are in use. Prior-art search answers { success, data } and its errors carry no code field. Patent-space and claim-validation routes answer the payload directly; patent-space errors carry a code, claim-validation errors do not.
Branch on the HTTP status rather than on the presence of a field, and treat code as absent unless the table for that endpoint lists one. We would rather say this than pretend the surface is more uniform than it is.