Developers · API v1
The cross-reference, over HTTP.
Send a manufacturer part number; get back the answer the XrefBase lookup gives, as JSON — the same six buckets, the same public sources, and the page to cite. No key, no account.
Who it is for
Procurement, PLM and BOM software that needs the next part number without a person typing the current one into a website. A cross-reference check belongs inside the tool where the part is already on screen: when a line goes on allocation, when an end-of-life notice lands, when a component engineer reviews a supplier's substitution.
It answers one question — what else will work, and on whose authority — and nothing about stock, price or datasheets. Every relationship it returns carries the public document it rests on.
Quickstart
One lookup is a GET. The part number here is a real one: TE retired it and named its successor in a product change notice.
curl "https://www.xrefbase.com/api/v1/alternatives?mpn=1-968880-3"const url = new URL("/api/v1/alternatives", "https://www.xrefbase.com");
url.searchParams.set("mpn", "1-968880-3");
// url.searchParams.set("manufacturer", "TE Connectivity");
const response = await fetch(url);
if (!response.ok) {
// 400: fix the request. 503: nobody checked —
// retry later; never record it as "no alternatives".
throw new Error((await response.json()).error.message);
}
const { result } = await response.json();
if (result.ambiguous) {
// More than one manufacturer carries this number.
// Ask which one (result.candidates), then look up
// again with it. Do not pick one yourself.
} else if (!result.matched) {
// Not assessed. Show result.message; never say
// "no alternatives".
} else {
// The only bucket that asserts substitutability:
console.log(result.verified_replacements);
// Cite this page wherever the answer is shown:
console.log(result.matched_part.url);
}{
"api_version": "1",
"retrieved_at": "2026-09-26T09:00:00.000Z",
"attribution": {
"source": "XrefBase",
"url": "https://www.xrefbase.com",
"cite": "When result.matched is true, link every answer you display to result.matched_part.url: the XrefBase page for that part, which shows each relationship with its public source. An unmatched or ambiguous answer has no part page; link it to the lookup instead, https://www.xrefbase.com/?mpn=<the part number you asked about>.",
"documentation": "https://www.xrefbase.com/developers"
},
"result": {
"query": {
"part_number": "1-968880-3",
"manufacturer": null
},
"matched": true,
"variants": [],
"ambiguous": false,
"mates_with": [],
"matched_via": "mpn",
"same_series": [],
"matched_part": {
"mpn": "1-968880-3",
"url": "https://xrefbase.com/part/te-connectivity/1-968880-3",
"series": "AMP MCP 2.8",
"category": "Terminals & Contacts",
"manufacturer": "TE Connectivity",
"also_known_as": []
},
"people_waiting": 0,
"verified_replacements": [
{
"mpn": "1-2141857-3",
"url": "https://www.xrefbase.com/part/te-connectivity/1-2141857-3",
"sources": [
{
"url": "https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/2859/E-20-012094.pdf",
"title": "TE E-20-012094",
"locator": "Description of Changes: 1-968880-3 obsolete and replaced by 1-2141857-3. (The PCN's replacement table lists the part as discontinued and leaves its Substitute Part Number column empty; the pairing is stated in the narrative.)",
"retrieved_at": "2026-09-05T12:03:58.375839+00:00"
}
],
"evidence": "Description of Changes: 1-968880-3 obsolete and replaced by 1-2141857-3. (The PCN's replacement table lists the part as discontinued and leaves its Substitute Part Number column empty; the pairing is stated in the narrative.)",
"relation": "supersedes",
"confidence": "high",
"source_url": "https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/2859/E-20-012094.pdf",
"manufacturer": "TE Connectivity"
}
],
"functional_equivalents": [],
"superseded_predecessors": []
}
}result is the database's answer, passed through verbatim — key order included. result.matched_part.url is the page to cite: it lists every relationship with its public source and always shows the current state, so a reader can check an answer your system cached months ago.
A single lookup puts the part number in the URL, where access logs keep it — yours, any proxy's, the CDN's. If the list of parts you are asking about is itself sensitive, use the batch endpoint: it is a POST for that reason.
The bucket contract
A matched answer has six arrays, often empty. The bucket a part arrives in is the claim XrefBase makes about it.
| Field | Claim | What it means |
|---|---|---|
verified_replacementsPublished replacements | Asserts substitution | The only results asserting a replacement relationship. Confirm application-specific fit before use. |
functional_equivalentsFunctional equivalents | Not a substitute | Similar function, not a confirmed drop-in. Engineering review is required before substitution. |
superseded_predecessorsSuperseded predecessors | Not a substitute | Product history, shown for context only — not an alternative to this part. |
same_seriesSame series | Not a substitute | Same family, different configuration. Family navigation, not a substitution claim. |
variantsVariants | Not a substitute | The same part in a different keying, colour or packaging suffix. |
mates_withMating counterparts | Not a substitute | What this component plugs into. These are never substitutes for it. |
Inside verified_replacements, relation says whose claim it is: supersedes is a supersession — the manufacturer replaced the part — and drop_in is a drop-in XrefBase has verified. Different claims by different authorities; show which. relation refines a claim within its bucket and never moves a part to another.
An empty bucket means nothing is recorded, not that nothing exists.
Integration rules
Break one of these and your product says something XrefBase does not.
- Never flatten the buckets. Not into one list, one table column, or one count called “alternatives” or “replacements”. Flattening is a correctness bug, not a presentation choice: it turns a mating counterpart into a suggested substitute.
- Never present context as an alternative. Only
verified_replacementsasserts substitutability.functional_equivalentsneed engineering review before anyone substitutes.superseded_predecessors,same_seriesandvariantsare history and family navigation.mates_withis what the part plugs into — the one part guaranteed not to substitute for it. - Always cite
matched_part.url. Link every matched answer you show to it, so a reader can see the source behind each relationship and whether it still stands. An unmatched or ambiguous answer has no part page — link it to the lookup,/?mpn=the number you asked about. - Unmatched means not assessed.
matched: falsewithambiguous: falsemeans XrefBase does not carry the part, or did not recognise the manufacturer you gave —messagesays which. Neither is a finding that no alternative exists, and neither may be shown as one. If you supplied a manufacturer, retry without it before concluding anything. - Ambiguous means ask.
ambiguous: truecomes withcandidatesand no buckets. Ask the user, or your own part master, which manufacturer is meant and look up again with it. Do not take the first candidate. - An error is not an answer. A
503, or a batch entry withstatus: "error", means nobody checked. Say you could not check, retry later, and never store it as an empty result. - Ignore fields you do not recognise. Fields may be added within v1 — the
urlon every related part arrived that way. None is removed or renamed without a new version path.
Status and errors
Matched, not assessed and ambiguous are all answers, so all three are a 200. Read result.matched and result.ambiguous, not the status code.
| Situation | Status | You get | Show |
|---|---|---|---|
| Part identified | 200 | matched: true, matched_part, the six buckets | Each non-empty bucket under its own heading, citing matched_part.url |
| Not in the catalogue | 200 | matched: false, ambiguous: false, message | Not assessed yet — never “no alternatives” |
| Manufacturer not recognised | 200 | The same, with a message naming the manufacturer | Nothing yet — retry without manufacturer |
| More than one manufacturer | 200 | ambiguous: true, candidates, no buckets | A choice of manufacturer |
| Invalid input | 400 | error.code: invalid_input and error.field | Nothing — fix the request |
| Lookup failed or timed out | 503 | lookup_unavailable or lookup_timeout, never cached | That you could not check — retry later |
{
"api_version": "1",
"error": {
"code": "invalid_input",
"message": "mpn is required.",
"field": "mpn"
}
}mpn is required; manufacturer is optional. Both are trimmed and limited to 80 characters. If a parameter is repeated, the first value is used — the same rule the lookup page follows.
Every response carries Access-Control-Allow-Origin: *, so the API can be called from a browser. Answers are Cache-Control: public, s-maxage=300, stale-while-revalidate=3600; errors and batches are no-store. retrieved_at is when the answer was read from the database, and a cached response keeps its original time.
Batch
Up to 50 lines of a bill of materials in one request.
The part numbers travel in the request body, so they never sit in a URL, a browser history or an access log. XrefBase neither logs nor stores them.
curl -X POST "https://www.xrefbase.com/api/v1/alternatives/batch" \
-H "Content-Type: application/json" \
-d '{"items": [
{"mpn": "1-968880-3"},
{"mpn": "DT04-3P", "manufacturer": "Deutsch"},
{"mpn": "ZAG 16"}
]}'{
"api_version": "1",
"retrieved_at": "2026-09-26T09:00:00.000Z",
"attribution": { … },
"results": [
{ "input": { "mpn": "1-968880-3" },
"status": "ok",
"result": { "matched": true, … } },
{ "input": { "mpn": "DT04-3P", "manufacturer": "Deutsch" },
"status": "ok",
"result": { "matched": true, "mates_with": [ … ], … } },
{ "input": { "mpn": "ZAG 16" },
"status": "ok",
"result": { "matched": false, "ambiguous": true,
"candidates": [ … ], … } }
]
}- One entry per item, in input order.
inputechoes the item exactly as you sent it. status: "ok"carriesresult— the same object a single lookup returns, with the same three shapes and the same rules.status: "error"carrieserror:invalid_inputfor a malformed line,lookup_unavailableorlookup_timeoutwhen nobody checked.- One bad line never fails the batch, so a well-formed request is always a
200. Checkstatuson every entry. - 1–50 items and at most 64 KiB per body, looked up 6 at a time with a 5-second limit per item. Over a limit is a
413(too_many_items,body_too_large); a body that is not JSON or has no items is a400(invalid_body).
Fair use
There are no API keys and no published rate limit yet. That is not a promise of unlimited capacity. What is enforced today is what this page lists: 50 items and 64 KiB per batch, 6 lookups at a time within one.
Single lookups are cached at the edge for five minutes and may be served up to an hour stale while the cache refreshes, so repeating one is cheap. Be proportionate beyond that: keep answers on your side, send a bill of materials as a batch rather than fifty single requests, and back off when you get a 503.
The full contract, with every schema and the bucket semantics in its descriptions, is the OpenAPI 3.1 document.