BOM Part Availability & Lead-Time Monitor
Pricing
from $10.00 / 1,000 part-supplier observeds
BOM Part Availability & Lead-Time Monitor
Reconcile a bill of materials with your own Mouser and DigiKey API keys. Resolves exact MPN and packaging, prices the order quantity, and reports stock, lead time, and lifecycle. Keeps a baseline and emits shortage, recovery, lead-time, and lifecycle changes. Demo mode needs no keys.
Pricing
from $10.00 / 1,000 part-supplier observeds
Rating
0.0
(0)
Developer
Olalekan Johnson
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Security
Limited permissionsShare
Unofficial. Not affiliated with Mouser, DigiKey, or the part manufacturers.
A buyer pastes a bill of materials and their own Mouser and DigiKey API credentials. This Actor asks those official APIs whether the exact manufacturer part number, in the packaging on the line, can cover the quantity that must actually be ordered. It prices the break that applies at that quantity, compares distributor stock with the order, and keeps a baseline so the next run can report a shortage, a recovery, a lead-time change, or a lifecycle change.
It does not place orders. It does not treat another part as electrically equivalent. It does not scrape distributor websites.
Who it is for
Small electronics procurement teams who already have a Mouser Search API key, a DigiKey Product Information API app, or both, and who need a repeatable shortage watch on a real BOM. A one-piece price and a reel of a different suffix are the wrong answer for a build that needs 2,000 pieces of tape-and-reel.
Demo mode is the default
Leave every credential empty and run with the default input. runMode is auto, so the Actor uses a bundled sample response set instead of calling Mouser or DigiKey. The sample is synthetic. It is not a quote.
The default run returns 12 dataset rows (6 sample parts × Mouser and DigiKey). Every row has demo: true, charged: false, and a demoNotice. Part observations are not charged. The only platform charge on a demo run is the start event, if you have enabled it.
The first demo run compares the sample with a bundled previous baseline, so the dataset contains real transition types:
| Line | Part | What the sample shows |
|---|---|---|
| U1 | TI LM358DR, 2,000, tape and reel | Mouser stock 800, so shortage. The 1-piece price is 0.48; the price used is the 1,000-piece break, 0.15. DigiKey reel MOQ 2,500 raises the order and can fulfill. Cut tape is noted and not used. |
| C12 | Murata GRM21BR71H104KA01L, 10,000 | Mouser multiple 4,000 raises the order to 12,000. |
| U3 | ST STM32G031K8T6, 500, tray | Mouser lists tube only, so the tray constraint is unmet and the tube price is not used. DigiKey tray MOQ 160 rounds the order to 640. |
| U7 | Analog Devices AD8606ARMZ, 100, tube | Mouser lead time moved from 8 weeks to 18. DigiKey lifecycle moved from active to NRND. A replacement mentioned in the sample is not copied into the row. |
| R4 | Yageo RC0805FR-0710KL, 5,000 | Mouser was short and now has stock: recovery. |
| U9 | TI SN74LVC1G08DBVR, 1,000, cut tape | Mouser returns a different manufacturer and a different suffix. DigiKey has no product. Both are empty shortages. The other MPNs are not recommended. |
Coverage on that first run is 9 complete, 1 partial, 2 empty. A later demo run of the same sample still returns 12 rows, and the event counts drop to zero because the baseline was saved. Give each BOM its own stateStoreName if you do not want schedules to share a baseline.
Force this path with runMode: "demo" even if keys are filled in. Demo never sends those keys.
Input
Put the BOM in bomJson, or bomCsv, or a public bomUrl. JSON wins, then CSV, then URL. Column names are case-insensitive. Spaces and underscores are ignored, so Manufacturer Part Number, mpn, and lineId all work.
lineId,manufacturer,mpn,quantity,packaging,currencyU1,Texas Instruments,LM358DR,2000,Tape & Reel,USD
[{"lineId": "U1","manufacturer": "Texas Instruments","mpn": "LM358DR","quantity": 2000,"packaging": "Tape & Reel","currency": "USD"}]
| Field | Required | What it does |
|---|---|---|
runMode | no | auto (default), demo, or live. Auto is demo until a selected supplier has credentials. |
suppliers | no | Default mouser and digikey. |
mouserApiKey | for live Mouser | Secret. Sent only to api.mouser.com. |
digikeyClientId, digikeyClientSecret | for live DigiKey | Secrets. Used only to obtain a client-credentials token. |
digikeyAccountId | no | Secret. Sent as X-DIGIKEY-Account-Id when your DigiKey app requires it. |
digikeySandbox | no | Call sandbox-api.digikey.com. |
digikeyLocaleSite | no | Two-letter site such as US or DE. Otherwise the site follows the line currency. Prices are still not converted. |
currency | no | Default USD when a line omits it. |
alertOnlyOnChange | no | Dataset keeps material changes only. Live mode still charges every successful check. The full set is in the LEDGER key. |
stateStoreName | no | Named key-value store for the baseline. Default bom-part-availability-state. |
maxBomLines | no | Default 200, maximum 500. Extra rows are counted and skipped. |
minRequestIntervalMs | no | Pause between official API calls. Default 250. |
A live run with only a Mouser key checks Mouser and marks DigiKey blocked for missing credentials. It does not fill DigiKey from the demo. An unknown supplier name is unsupported and is not scraped.
bomUrl must be http or https on port 80 or 443, with no username or password in the URL. Localhost, .local, .internal, private, loopback, and link-local addresses are rejected, including after a redirect.
How a row is decided
- The MPN must match exactly. Case and internal spaces are ignored. Punctuation stays, so
SN74LVC1G08DBVRis notSN74LVC1G08DBVRG4. - The manufacturer must match when you supplied one.
TImatches Texas Instruments.STmatches STMicroelectronics. Maxim does not match Analog Devices. If you leave the manufacturer blank and two manufacturers share the MPN, the line is ambiguous and neither is chosen. - The packaging constraint selects only that packaging of the same MPN. Tape and reel, partial reel (Digi-Reel, MouseReel), cut tape, tray, tube, bulk, and ammo are recognized. Other packagings are described in
nonSelectedPackagingNoteand are not used for price or stock. - Order quantity is the BOM quantity, raised to the minimum order quantity when that minimum is higher, then rounded up to the order multiple. A DigiKey cut-tape offer does not inherit the full-reel standard package as its multiple.
- The unit price is the highest break at or below that order quantity, in the requested currency. A cheaper 1-piece break is stored as
onePieceUnitPriceand is used only when the order really falls on that break (usedOnePiecePrice). A higher tier is never used. Another currency is a mismatch, not a conversion. When DigiKey returns My Pricing, that list wins over standard pricing. canFulfillis distributor stock versus the order quantity. Factory stock and quantity on order are reported and are not added to available stock.- Lead time comes from the selected packaging.
84 Daysbecomes 12 weeks. Lifecycle maps NRND, EOL, obsolete, last-time-buy, and DigiKey "Not For New Designs". The worst status wins. Conflicting sources lower the confidence and keep coverage atpartial.
mayBeCached is true only when the supplier response Age is greater than zero or X-Cache contains hit. DigiKey is called with Product Details, not keyword search. DigiKey documents that keyword results can be cached for up to 24 hours, so keyword search is not used. Demo rows are never cached quotes.
Coverage is complete only when identity, packaging, currency, price, stock, lead time, and lifecycle are all present on a first-party offer and the manufacturer was supplied. A matched part with a gap is partial. No exact part is empty. An HTTP or credential failure is blocked. A supplier this Actor does not call is unsupported.
equivalentSubstitute is always false.
Output example
This is the Mouser row for U1 from the bundled demo, including the shortage against the bundled baseline. The same keys are present on every row. Missing values are null.
{"packagingConstraint": "Tape & Reel","packagingSelected": "Tape & Reel","supplierPartNumber": "595-LM358DR","manufacturerMatched": "Texas Instruments","mpnMatched": "LM358DR","description": "IC OPAMP GP 2 CIRCUIT 8SOIC","sourceUrl": "https://www.mouser.com/ProductDetail/Texas-Instruments/LM358DR","datasheetUrl": "https://www.mouser.com/datasheet/demo/LM358DR","rohsStatus": "RoHS Compliant","evidenceHash": "e46e71ed6bb4041d2d7a4fa4ae08e957b5117468ed0fa8870adbd09ae44181a0","evidenceSnippet": "{\"currency\":\"USD\",\"leadTime\":\"16 Weeks\",\"lifecycle\":\"active\",\"manufacturer\":\"Texas Instruments\",\"mpn\":\"LM358DR\",\"orderQuantity\":2000,\"packaging\":\"Tape & Reel\",\"quantityAvailable\":800,\"sourceUrl\":\"https://www.mouser.com/ProductDetail/Texas-Instruments/LM358DR\",\"supplier\":\"mouser\",\"supplierPartNumber\":\"595-LM358DR\",\"unitPrice\":\"0.15\"}","errorMessage": null,"priceSource": "standard_pricing","orderMultipleSource": "supplier_multiple","leadTimeRaw": "16 Weeks","lifecycle": "active","lifecycleRaw": "Active","identityNote": null,"nonSelectedPackagingNote": null,"observedPackagings": null,"sourceCurrency": "USD","previousLifecycle": "active","previousObservedAt": "2026-09-15T12:00:00Z","previousUnitPrice": "0.15","unitPrice": "0.15","extendedPrice": "300.00","onePieceUnitPrice": "0.48","nonSelectedMinUnitPrice": null,"digiReelFee": null,"priceBreaksJson": "[{\"quantity\":1,\"unitPrice\":\"0.48\",\"currency\":\"USD\"},{\"quantity\":10,\"unitPrice\":\"0.36\",\"currency\":\"USD\"},{\"quantity\":100,\"unitPrice\":\"0.22\",\"currency\":\"USD\"},{\"quantity\":1000,\"unitPrice\":\"0.15\",\"currency\":\"USD\"},{\"quantity\":2500,\"unitPrice\":\"0.12\",\"currency\":\"USD\"}]","orderQuantity": 2000,"quantityAvailable": 800,"stockVersusRequired": -1200,"stockVersusOrder": -1200,"moq": 1,"orderMultiple": 1,"standardPackage": null,"applicableBreakQuantity": 1000,"factoryStock": 12000,"quantityOnOrder": 5000,"httpStatus": 200,"leadTimeDays": 112,"leadTimeWeeks": 16,"previousLeadTimeWeeks": 16,"canFulfill": false,"previousCanFulfill": true,"observationId": "97b4fd8d4b98f1cb93a79f655a928b47","runMode": "demo","supplier": "mouser","bomLineId": "U1","lineIndex": 1,"manufacturer": "Texas Instruments","mpn": "LM358DR","requiredQuantity": 2000,"requestedCurrency": "USD","coverage": "complete","confidence": "high","observedAt": "2026-10-23T04:00:00Z","substituteNote": "No other part is treated as electrically equivalent. A different package, a near-miss MPN, or a replacement mentioned by the supplier is not a recommendation.","affiliation": "Unofficial. Not affiliated with Mouser, DigiKey, or the part manufacturers.","baselineSource": "bundled_demo_baseline","stateKey": "d-a949bf71a2813cd7808c2b12e2e371462ddb89238c76499824ff78e80b342c0b","stateIdentity": "demo|mouser|texas instruments|LM358DR|tape_reel|USD","events": "shortage","dataSource": "bundled-demo-fixture","demoNotice": "DEMO DATA. Computed from a bundled sample response set, not from a live Mouser or DigiKey call. demo=true. Part-supplier observations are not charged in demo mode.","fulfillmentReason": "stock_short","lifecycleSource": "supplier","cacheNote": "Bundled demo fixture. Not a live supplier response, and not a quote.","rejectedNonExactCount": 0,"manufacturerMismatchCount": 0,"candidateCount": 1,"demo": true,"materialChange": true,"charged": false,"equivalentSubstitute": false,"statePersisted": true,"eventShortage": true,"eventRecovery": false,"eventLeadTimeChange": false,"eventLifecycleChange": false,"eventPriceChange": false,"eventFirstObserved": false,"eventCheckFailed": false,"identityMatched": true,"packagingMatched": true,"usedOnePiecePrice": false,"currencyMatchesRequest": true,"marketplace": false,"moqRaised": false,"multipleRounded": false,"deliveredToDataset": true,"mayBeCached": false,"sourceReportedAReplacement": false}
The run's default key-value record OUTPUT for that same demo:
{"actor": "bom-part-availability-monitor","title": "BOM Part Availability & Lead-Time Monitor","version": "1.0.0","demo": true,"runMode": "demo","finishedAt": "2026-10-23T04:00:00Z","bomLineCount": 6,"invalidLineCount": 0,"duplicateLinesSkipped": 0,"truncatedLineCount": 0,"observationCount": 12,"datasetRecordCount": 12,"chargedUnits": 0,"chargeEvent": "part-supplier-observed","suggestedUnitPriceUsd": "0.01","stoppedReason": null,"notDeliveredBecauseChargeLimit": 0,"coverage": {"complete": 9,"partial": 1,"empty": 2,"blocked": 0,"unsupported": 0},"events": {"shortage": 3,"recovery": 1,"lead_time_change": 1,"lifecycle_change": 1,"price_change": 0,"first_observed": 0,"check_failed": 0,"input_rejected": 0},"canFulfillCount": 8,"cannotFulfillCount": 4,"unknownFulfillmentCount": 0,"suppliers": ["mouser","digikey"],"stateStoreName": "bom-part-availability-state","stateKeysWritten": 12,"stateKeysPreserved": 0,"stateUnreadableCount": 0,"alertOnlyOnChange": false,"demoNotice": "DEMO DATA. Computed from a bundled sample response set, not from a live Mouser or DigiKey call. demo=true. Part-supplier observations are not charged in demo mode.","substitutePolicy": "No other part is treated as electrically equivalent. A different package, a near-miss MPN, or a replacement mentioned by the supplier is not a recommendation.","affiliation": "Unofficial. Not affiliated with Mouser, DigiKey, or the part manufacturers.","partialDueToChargeLimit": false}
LEDGER holds every observation from the run. In alert-only mode the dataset is the subset where materialChange is true, and the ledger still has the quiet checks.
Events and the baseline
events is a pipe-separated list, in this order:
| Event | When it is set |
|---|---|
shortage | The part could be fulfilled and now cannot, or this is the first observation and it cannot. |
recovery | It could not be fulfilled and now can. |
lead_time_change | Both lead times are numeric and differ by at least one week. |
lifecycle_change | Both lifecycles are known and differ. unknown does not count. |
price_change | Same currency and the unit price moved by at least 0.5%. |
first_observed | No baseline existed yet. |
check_failed | The call was blocked, or the saved baseline could not be read. No shortage is inferred from a missing baseline. |
input_rejected | The line failed validation, or the supplier is unsupported. |
Only complete, partial, and empty update the named state store, and only after a live charge succeeds (demo writes without charging). blocked and unsupported leave the previous snapshot in place. A run that ends in an exception does not mark last-successful-run. A run that stops because the charge limit was reached is a partial success: the observations already charged stay as the new baseline, and the parts not reached keep the old one.
State keys are separate for demo and live, so a demo schedule cannot overwrite a live baseline.
Pricing
This Actor uses pay-per-event pricing. There is no per-dataset-item charge, so a row is never billed twice.
| Event | Price | When it is charged |
|---|---|---|
apify-actor-start | $0.005 | Every run, including demo. This is the platform start event. |
part-supplier-observed | $0.01 | One live observation whose coverage is complete, partial, or empty. |
Demo runs do not charge part-supplier-observed. Blocked, unsupported, and rejected lines are not charged. A repeated observation id in the same run is not charged twice. Alert-only mode still charges each successful live check, because the check is the product. Quiet rows are in LEDGER.
Worked examples:
| Run | Arithmetic | Total |
|---|---|---|
| Demo daily test, no keys | Start event only | $0.005 |
| Pilot: 25 parts, both suppliers, one live run | 50 × $0.01 + $0.005 | $0.505 |
| Daily watch: 50 parts, both suppliers, 30 days | 3,000 × $0.01 + 30 × $0.005 | $30.15 |
A maximum charge stops the run cleanly. After the start fee, each further $0.01 pays for one observation. The Actor writes an observation only when the charge succeeds, then stops if that charge reports the limit. An observation the platform refuses is not written and does not replace its baseline. OUTPUT.notDeliveredBecauseChargeLimit counts the parts left unchecked, and partialDueToChargeLimit is true. On a $5 cap, the start fee leaves about $4.995, which pays for 499 observations at $0.01 ($4.99). What happens to the next $0.01 depends on the platform's remaining-budget rule. If that charge is accepted and flagged as the limit, the row is delivered and the run stops. If it is refused, that row is omitted and the run stops. Either way the earlier rows keep their new baseline.
Your Mouser and DigiKey quotas are yours. This price does not include their fees.
Scope and limits
- Official HTTP APIs only. Mouser Search API
partnumberwith the exact option, batched up to 10. DigiKey Product Information v4 Product Details, one MPN at a time, after a client-credentials token. Hosts areapi.mouser.com,api.digikey.com, andsandbox-api.digikey.com. Redirects are not followed. Calls carry a User-Agent that identifies this Actor and the contact address below. - Calls are throttled and retried on 429 and 5xx with backoff. Secrets are redacted from error text.
- The customer must comply with the Mouser and DigiKey API terms. Do not use the output to build a public parts database. The data belongs to the response you were authorized to request.
- No ordering, shopping cart, AVL, date-code, or contract-price file. A Digi-Reel fee is reported and is not added into
extendedPrice. - Empty results are real answers and are charged. They can turn a previously fulfillable part into a shortage.
- Marketplace offers are used only when no first-party offer matched, and then coverage stays partial.
- The sample catalog is six parts. A demo MPN outside that catalog is
emptywith reasonnot_in_demo_catalogand no invented price. - Default memory is 512 MB, with a floor of 256 MB and a ceiling of 1024 MB. A few hundred lines finish well inside a one-hour run timeout.
Integrations
Schedule the Actor daily in Apify. Point a webhook, n8n, or Make scenario at the dataset or at the OUTPUT key.
- Filter rows where
eventscontainsshortage,recovery,lead_time_change, orlifecycle_change. - Use
alertOnlyOnChangewhen the webhook should stay quiet, and readLEDGERwhen you want the full check. - Send the flat dataset to Google Sheets. Prices are decimal strings (
0.15,0.0082) so a spreadsheet does not have to guess. Text that could look like a formula is prefixed with a quote. - Join back to your BOM on
bomLineIdor on manufacturer + MPN + packaging + currency. - Keep a separate
stateStoreNameper customer or per BOM.
Run it locally
Python 3.12.
pip install -r requirements.txtpip install pytest pytest-asynciopytestmkdir -p storage/key_value_stores/defaultecho '{}' > storage/key_value_stores/default/INPUT.jsonAPIFY_LOCAL_STORAGE_DIR="$PWD/storage" python -m src
The empty input prints a demo summary and writes storage/datasets/default/. chargedUnits in OUTPUT is 0.
Questions: plusonecares@gmail.com.
FAQ
Why is the unit price higher than the 1-piece price on the same page?
The 1-piece break does not apply to a build that must order thousands. unitPrice is the break at the order quantity. onePieceUnitPrice is there so you can see what was not used.
Will it suggest a drop-in replacement when the part is short?
No. A different suffix, a different package, and a replacement named by the supplier are reported as not used. equivalentSubstitute stays false. You decide whether any other part is acceptable.
Does alert-only mode make unchanged days free? No. In live mode every successful observation is charged once. Alert-only mode only changes which rows are copied into the dataset.
A supplier returned 401. Did it wipe yesterday's good stock figure?
No. Blocked and unsupported results are not charged and do not replace the baseline. The row explains the failure. If every live row is blocked, the run fails after writing those explanations, and last-successful-run is left as it was.
Can I price EUR from a USD break? No. The line's currency is sent to DigiKey as the currency header, and Mouser prices in another currency are a mismatch. Nothing is converted.
Whose API quota is this? Yours. The keys stay in secret inputs and are sent only to the official hosts.