Bowmark AIdocs

PC Parts (multi-retailer)

Price a PC part across Newegg, Micro Center, and B&H with one call — Bowmark searches all three in parallel and returns price-sorted offers — then read…

Price a PC part across Newegg, Micro Center, and B&H with one call — Bowmark searches all three in parallel and returns price-sorted offers — then read any Micro Center result in full for the manufacturer part number, whether it is actually buyable, and the store's whole spec sheet. Compose a build by calling search per part and sourcing each from the cheapest store.

Also known as: pc, parts, components, gpu, cpu, build, graphics card, video card, ssd, hard drive, ram, memory, motherboard, power supply, psu, cpu cooler, pc part, computer part, monitor, rtx, geforce, radeon, nvidia, ryzen, intel core, graphics cards

Call it

bowmark.pcparts.search(query: string, options?: CallOptions): Promise<OfferSearchResult>
bowmark.pcparts.getProduct(urlOrOffer: string | Offer, options?: CallOptions): Promise<ProductResult>

Functions

FunctionWhat it does
searchSearches Newegg + Micro Center + B&H for ONE part (e.g. "Ryzen 7 7800X3D" or "RTX 4070") in parallel, keeps the cards that match the part, and returns { offers, warnings } — price-sorted…
getProductReads ONE product page in full — pass a product URL or an offer straight from search. Returns the identity a search row cannot carry (sku, and the mpn that makes a cross-store…

Types

type Offer = {
  store: "newegg" | "microcenter" | "bhphoto"   // where this offer is from
  title: string                                  // the product as the store lists it
  price: number | null                           // USD; null if unpriced
  url: string | null                             // product page
}
type OfferSearchResult = {
  offers: Offer[]        // ONE part across ALL retailers, price-sorted (cheapest first)
  warnings: string[]     // always present; names any store that did not answer. A
                         // store named here priced NOTHING, so "the cheapest of three"
                         // was really the cheapest of two — read this before sourcing
}
// Compose a build by calling search per part and picking the cheapest offer each
// time, and carry warnings through to the plan so a partial quote says so.

type CallOptions = {
  timeoutMs?: number   // per-provider budget in ms, default 30000, clamped to 1000-55000.
                       // A provider slower than this is DROPPED from the results and
                       // NAMED in warnings — never silently absent
}

// What getProduct adds: the fields only a product page carries. Every one is
// nullable because stores genuinely omit them — null means "this store does not
// report it for this product", never "we failed to read it", and every null is
// also named in warnings.
type Spec = { group: string; name: string; value: string }  // the store's own grouping
type Product = {
  store: "microcenter"            // NARROWER than Offer.store on purpose: search
                                  // covers 3 stores, getProduct reads 1. newegg
                                  // and bhphoto join this union as their own
                                  // getProduct lands; today they THROW.
  url: string                     // canonical product URL on that store
  title: string
  brand: string | null
  sku: string | null              // the STORE's stock number — its id, not portable
  mpn: string | null              // manufacturer part number — the id that IS
                                  // portable; same mpn = same physical part
  price: number | null
  currency: string
  availability: string | null     // "InStock" / "OutOfStock" / "PreOrder" — the
                                  // thing search cannot tell you, because a grid
                                  // prices an item whether or not it is buyable
  rating: number | null
  description: string | null
  images: string[]
  specs: Spec[]                   // the store's full spec sheet, ungrouped by us
}
type ProductResult = {
  product: Product
  warnings: string[]              // always present; names what the store omitted
}

Examples

// Source a whole PC build — for each part, price it across all 3 stores and
// buy from the cheapest. Returns the sourcing plan + the per-store comparison.
const parts = [
  "AMD Ryzen 7 7800X3D", "GeForce RTX 4070", "Samsung 990 Pro 2TB",
  "Corsair Vengeance 32GB DDR5 6000", "Seasonic Focus 750W Gold", "Fractal Design North case",
];
const build = await Promise.all(parts.map(async (part) => {
  const { offers, warnings } = await bowmark.pcparts.search(part);   // all 3 stores in parallel
  for (const w of warnings) log(`${part}: ${w}`);
  const cheapest = offers[0] || null;
  const prices = {};                                   // one price per store, for the comparison
  for (const o of offers) if (prices[o.store] == null) prices[o.store] = o.price;
  log(`${part}: ${cheapest ? "$"+cheapest.price+" @ "+cheapest.store : "no match"}  ${JSON.stringify(prices)}`);
  // Carry the warning through: a part priced while a store was down was NOT
  // shopped across three stores, and the plan should say so rather than imply it.
  return { part, buyFrom: cheapest?.store ?? null, price: cheapest?.price ?? null, url: cheapest?.url ?? null, prices, missedStores: warnings };
}));
const total = build.reduce((s, b) => s + (b.price || 0), 0);
return {
  total,
  storesUsed: [...new Set(build.map(b => b.buyFrom).filter(Boolean))],
  fullyShopped: build.every(b => b.missedStores.length === 0),
  build,
};
// Search, then actually LOOK at the part before buying it. A search row is a
// title and a price — it cannot tell you whether the thing is in stock, or
// whether two stores' listings are even the same physical part.
const { offers, warnings } = await bowmark.pcparts.search("Samsung 990 PRO 1TB");
for (const w of warnings) log(w);
const readable = offers.filter(o => o.url && o.store === "microcenter");   // the store getProduct reads today
if (!readable.length) return { note: "no readable offer", offers, warnings };

const { product, warnings: unreported } = await bowmark.pcparts.getProduct(readable[0]);
log(`${product.title} — $${product.price} — ${product.availability}`);
log(`mpn ${product.mpn}, ${product.specs.length} specs, unreported: ${unreported.join("; ") || "nothing"}`);

// The two things a search row could never answer.
const buyable = product.availability === "InStock";
const capacity = product.specs.find(s => /capacity/i.test(s.name))?.value ?? null;
return { buyable, mpn: product.mpn, capacity, price: product.price, unreported, storesMissed: warnings };

Providers behind it

Provider
neweggNewegg
microcenterMicro Center
bhphotoB&H Photo