Match a price list to IX IDs
Send a supplier price list or your own parts list, get an IX ID for every row we can identify, and a short list of rows a person must decide.
This is a worked example, not a supported connector. Interchange does not build or run connectors. You own the code you write from it, and the support boundary applies. Read the support boundary.
This recipe needs an API key on a plan that includes the endpoint. Read the key from an environment variable and never put it in a web page.
How it works
Send the rows in batches
One call takes up to 1,000 rows. Give each row your own
ref, which comes back unchanged, and the part number or description astext. Addbrandwhen you know it, because it narrows a part-number match.Sort the answers
Each row has its own status.
matchedwithidentified_byofexact_codeis a mapped part number, and safe to accept as the link. Everything else goes to a person:ambiguouslists candidates,no_verified_matchmeans we do not know, and a description-only match is a hint, not an answer.Keep the safety flags with the row
A matched row carries the flags of its item. Store them next to the IX ID you store, so a later view of your list can still show them.
Store IX IDs as opaque keys
Do not parse an IX ID or build one yourself. Store it and send it back.
The code
Node 22, no libraries. Adapt it to your language and your storage.
const BASE = "https://api.interchangeparts.com.au";
const KEY = process.env.INTERCHANGE_API_KEY; // only the keyed endpoints need it
async function call(path, init = {}) {
const response = await fetch(BASE + path, {
...init,
headers: { Accept: "application/json", ...(KEY ? { Authorization: "Bearer " + KEY } : {}), ...init.headers },
});
// Errors are application/problem+json, success is application/json. Both parse as JSON.
return { status: response.status, body: await response.json(), requestId: response.headers.get("Interchange-Request-Id") };
}
// rows: [{ ref: "your-own-row-id", text: "the part number or description in your price list", brand: "optional" }]
export async function matchPriceList(rows) {
const decided = [];
const forReview = [];
// One call takes up to 1,000 rows. Rows are answered in the order sent, each with its own status.
for (let i = 0; i < rows.length; i += 1000) {
const chunk = rows.slice(i, i + 1000);
const { status, body, requestId } = await call("/v1/match", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ rows: chunk }),
});
if (status !== 200) throw new Error(body.code + " (request " + requestId + ")");
for (const result of body.results) {
if (result.status === "matched" && result.identified_by === "exact_code") {
decided.push({ ref: result.ref, ixId: result.ix_id, safetyFlags: result.safety_flags ?? [] });
} else {
// ambiguous, no_verified_match, or only a description match: a person decides. Never pick one for them.
forReview.push(result);
}
}
}
return { decided, forReview };
}
Watch for
- Batch matching needs an API key on a plan that includes it. Without one you get a 401 or a 403.
- Your rows are used to answer the request and are not added to the public catalogue.
- A row we cannot match is not a row with no equivalent. Treat
no_verified_matchas unknown.
The calls are described in the API reference.