# PCN-to-BOM Impact Extractor (`amycole/pcn-to-bom-impact-extractor`) Actor

Beta: Match saved NXP discontinuation HTML and selected TI/onsemi PCN PDFs to exact BOM rows. Return typed deadlines, source evidence and explicit review states. Direct URL retrieval is experimental.

- **URL**: https://apify.com/amycole/pcn-to-bom-impact-extractor.md
- **Developed by:** [amycole](https://apify.com/amycole) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $350.00 / 1,000 processed notices

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PCN-to-BOM Impact Extractor

Find which exact BOM rows occur in supported electronic-component change or discontinuation notices. Keep the original row, product and revision identifiers, typed deadlines, source locations and explicit extraction failures. Use the results to route purchasing and engineering reviews into your existing workflow.

**Beta release.** Supports the document structures below. Direct URL retrieval is experimental; the tested cloud path uses saved documents supplied as base64. No universal manufacturer coverage or market-wide accuracy is claimed.

### Try the example

The form is prefilled with a small **synthetic** NXP-style notice and three synthetic BOM rows. Run it to see two exact matches and one unmatched row. This demonstrates the pipeline, not a real announcement. For your own data, replace the documents and BOM, and set `synthetic_bom` to `false`.

### Supported documents

| Adapter | Supported structure | Important limits |
| --- | --- | --- |
| NXP | Discontinuation HTML with the seven-column affected-parts table and MPN/12NC values | Individual last-buy and last-delivery dates; the NXP replacement column is not returned |
| Texas Instruments | Selected change and discontinuance text PDFs with explicit affected lists | Affected MPNs are separate from recommended replacements; reinstatements, strikethrough revisions and uncertain annotations need review |
| onsemi | Selected final product/process-change text PDFs with verified numbered English pages | Standard parts only; qualification vehicles are separate; customer-specific addenda are not processed |

Text PDFs must contain machine-readable text. Scans/OCR, Product Bulletins, IPCNs, onsemi PD notices, ranges and unsupported layouts are rejected or marked partial. A manufacturer name alone does not establish layout compatibility. Missing deadlines remain unresolved. Contradictory printed TI order/ship dates remain in `unresolved_deadlines`, with their original dates and evidence; they are not silently corrected.

### Prepare your input

Use contract `schema_version: "0.3"`, 1–10 `documents`, and **exactly one** of `bom_rows` or `bom_csv`. Each document needs its expected printed `notice_id`, `manufacturer`, and `content_base64`. An optional public HTTPS `source_url` records the evidence origin; with inline content, no URL is fetched. `input_notice_ref` is your own document identifier. Only supply `supersedes_notice_id` when you have verified that relationship.

Each BOM row requires string `row_id`, `manufacturer`, `mpn`, `product_id`, `revision`; optional `part_scope` is `standard`, `custom` or `unknown`. Preserve the complete orderable MPN, including packaging suffixes, commas and slashes. Matching trims outer whitespace and uses explicit manufacturer aliases; it does not infer a family or engineering equivalence. onsemi PDF typographical hyphens U+2010/U+2011 are normalized, with a warning and the source spelling retained in extracted evidence.

For CSV, use these headers and keep identity columns as strings:

```csv
row_id,manufacturer,mpn,product_id,revision,part_scope
001,NXP,"PART001,115",PRODUCT-A,002,standard
```

Prepare a saved notice and CSV using Python's standard library:

```python
import base64, json
from pathlib import Path
raw = Path("notice.pdf").read_bytes()
if not 0 < len(raw) <= 5_000_000:
    raise ValueError("Document exceeds the supported size")
payload = {
    "schema_version": "0.3", "synthetic_bom": False,
    "documents": [{"notice_id": "REPLACE_WITH_PRINTED_ID",
                   "manufacturer": "TI",
                   "content_base64": base64.b64encode(raw).decode("ascii")}],
    "bom_csv": Path("bom.csv").read_text(encoding="utf-8-sig"),
}
with Path("actor-input.json").open("x", encoding="utf-8") as f:
    json.dump(payload, f)
```

Paste the prepared JSON into the Actor input's JSON editor. Remove the prefilled `bom_rows` when using `bom_csv`. Keep the file private: it contains your notice and BOM. The development source package also includes `tools/make_actor_input.py` for multiple documents, validation and safe relative file paths.

Limits: 10 documents, 1,000 BOM rows, 5,000,000 bytes per document, 100 PDF pages. Source-URL-only inputs accept public HTTPS on `www.nxp.com`, `www.onsemi.com`, `www.mouser.com`, `www.farnell.com` and `mm.digikey.com`, without credentials, queries or fragments. Redirects and DNS addresses are checked. No authentication or access controls are bypassed. The observed NXP cloud URL request returned HTTP 404; use a saved original rather than relying on URL retrieval for a production workflow.

### Read the outputs

The default Dataset contains **every notice × BOM-row evaluation**. The default Key-value store contains:

| Key | Content |
| --- | --- |
| `OUTPUT` | JSON: run state, acquisition and notice reports, summary, all results and revision deltas |
| `IMPACTS_CSV` | Matched rows, including inactive historical matches |
| `REVIEWS_CSV` | Manual-review and failed rows |
| `ALL_RESULTS_CSV` | Every evaluation |

Read `OUTPUT.run_state` and `notice_reports` even when the Apify run says Succeeded. `partial` can preserve valid positive matches while leaving other documents, dates or scope unresolved. If all documents fail, output is saved before the run exits unsuccessfully. Invalid batch input is rejected before acquisition, with a stable error code in `OUTPUT`.

| Result status | Meaning |
| --- | --- |
| `matched` | Exact affected-list match; not an engineering or supply decision |
| `no_match_in_listed_scope` | No match in that successfully processed list; not universal absence of impact |
| `out_of_scope` | Different manufacturer |
| `manual_review` | Incomplete extraction, unknown manufacturer or unresolved part scope |
| `failed` | That document could not be acquired or extracted |

Deadlines retain their kinds, printed text and source positions. Last-time-buy, last-time-delivery and proposed first shipment have different meanings. Recommended TI replacements and onsemi changed part numbers are distinct fields; neither certifies equivalence. Cybersecurity-support terms and relative acknowledgement deadlines require review.

Verified complete superseding notices can retire an earlier notice within the same input batch. Filter `notice_active` before counting current impacts. Revision deltas are batch-local; this Actor does not maintain a shared historical database. `complete` describes the processed table and does not certify that every commercial condition is resolved.

CSV uses UTF-8 with BOM and escapes formula prefixes; JSON preserves original values. Retrieve all pages of the Dataset for larger batches, or download the stored `ALL_RESULTS_CSV`. Key existence and a successful run alone do not establish that you received the whole result.

### API and AI workflows

Submit the same input JSON through the Apify API or an Actor-calling tool. Await the completed run, fetch `OUTPUT`, inspect its business state, and retrieve the Dataset or CSVs before updating your system. Use the original `row_id`, `product_id`, `revision` and document reference to join results back to your BOM. A web search does not provide this full cross-product, row identity, typed date evidence or failure accounting. MCP compatibility itself is not a quality guarantee; external API/MCP end-to-end acceptance is still pending.

### Data handling

Documents are processed in temporary local files. Application logs contain aggregate counts and stable errors, not BOM values or document text. Input and output are stored in the run's Apify storage; temporary-file removal is **not** deletion of `INPUT`. No data is incorporated into a shared customer database.

Retention depends on your Apify plan and storage configuration. Named storages are retained indefinitely; unnamed storage follows platform retention rules. Do not assume automatic deletion after a short fixed period. Download required records, then explicitly delete the run and associated storages when appropriate. Keep input, output, storage IDs and signed links restricted. This Actor offers no zero-retention guarantee. See [Apify storage documentation](https://docs.apify.com/storage) for current rules. Process documents you are entitled to use; original manufacturer PDFs are not redistributed with the demonstration.

### Verification and release limits

Development has observed 30 selected real notices. In the latest 12-notice diagnostic set, fixes were checked against 64 fully transcribed PDF affected parts, 12 sampled NXP rows and 24 sampled NXP part dates. One reinstatement notice is deliberately rejected. Repaired cases are not a new blind benchmark; no 98% accuracy claim is supported. 105 regression tests passed with local originals, covering extraction, identity preservation, budget rejection, save-before-charge and repeat-run protection.

The preceding private build saved a 10-document × 1,000-row batch: 10,000 evaluations, about 10 seconds, maximum observed memory 204.3 MB and displayed execution cost $0.051. The BOM repeated 29 synthetic patterns. These values are one capacity observation, not a performance SLA or total cost: retention, reading, billing, support and different layouts can change the cost. Full cloud Dataset, OUTPUT and CSV exports were retrieved and compared for the 10,000-evaluation capacity run and the corrected 160-evaluation diagnostic run. Every CSV row identity was checked. These selected cases do not certify every layout.

### Pricing and interrupted runs

A processed notice is $0.35, plus $0.01 per run start with the supported maximum 1 GB memory. A complete or partial extracted notice is billable even when no BOM row matches. Failed notices have no custom notice charge; the start fee still applies. There is no per-BOM-row charge. Platform execution usage is included in these event prices; normal Apify account/storage terms still apply.

Set a maximum cost sufficient for the entire input batch: $0.01 + $0.35 × document count (for example $0.36 for one, $3.51 for ten). The budget preflight uses the current event prices, including applicable discounts. Insufficient budget is rejected before acquisition, preserving cross-notice revision semantics. All JSON and CSV exports are saved before notice charging. If a run is interrupted after writing begins, do not resurrect it: same-run restarts are rejected and original outputs are preserved to prevent duplicate writes and charges. Start a new run only if a fresh execution is required. Inspect `OUTPUT.billing` and the platform charge breakdown.

# Actor input Schema

## `schema_version` (type: `string`):

Use 0.3.

## `documents` (type: `array`):

1–10 notices: printed notice_id, manufacturer, and content_base64 from a saved document. Optional evidence source_url, input_notice_ref and verified supersedes_notice_id. Direct URL retrieval from the allowlisted public domains is experimental and may fail. No credentials; 5 MB per document. Prefill is a synthetic demonstration, not a real manufacturer announcement.

## `bom_rows` (type: `array`):

Use this or bom_csv, not both. Each object must contain string row_id, manufacturer, mpn, product_id, revision; optional part_scope: standard/custom/unknown. Orderable MPNs are matched exactly.

## `bom_csv` (type: `string`):

Use instead of bom_rows; headers row_id,manufacturer,mpn,product_id,revision, optional part_scope. UTF-8; values remain strings. Remove bom_rows from input when using CSV.

## `synthetic_bom` (type: `boolean`):

The prefilled demonstration is synthetic. Set false when using your own BOM.

## Actor input object example

```json
{
  "schema_version": "0.3",
  "documents": [
    {
      "notice_id": "202607010DN",
      "manufacturer": "NXP",
      "input_notice_ref": "synthetic-cloud-pipeline",
      "content_base64": "PGh0bWw+PGgxPjIwMjYwNzAxMEROIDogU3ludGhldGljIGV2YWx1YXRpb24gbm90aWNlPC9oMT48dGFibGU+PHRyPjx0aD5QQ04gVHlwZTwvdGg+PHRoPklzc3VlIERhdGU8L3RoPjx0aD5FZmZlY3RpdmUgRGF0ZTwvdGg+PC90cj48dHI+PHRkPkRpc2NvbnRpbnVhdGlvbiBOb3RpZmljYXRpb248L3RkPjx0ZD4xNC1KdWwtMjAyNjwvdGQ+PHRkPjE1LUp1bC0yMDI2PC90ZD48L3RyPjwvdGFibGU+PHRhYmxlPjx0cj48dGg+UGFydCBOdW1iZXIgLyAxMk5DPC90aD48dGg+RGlzY29udGludWF0aW9uIFR5cGU8L3RoPjx0aD5BdmFpbGFiaWxpdHk8L3RoPjx0aD5Tb3VyY2U8L3RoPjx0aD5MYXN0IFRpbWUgQnV5IERhdGU8L3RoPjx0aD5MYXN0IFRpbWUgRGVsaXZlcnkgRGF0ZTwvdGg+PHRoPlJlcGxhY2VtZW50IFBhcnQ8L3RoPjwvdHI+PHRyPjx0ZD5URVNUMDAxLUEgKDEyMzQ1Njc4OTAxMik8L3RkPjx0ZD5GVUxMIFdJVEhEUkFXQUw8L3RkPjx0ZD5MaW1pdGVkIEF2YWlsYWJpbGl0eTwvdGQ+PHRkPlNvbGUgU291cmNlPC90ZD48dGQ+MTQtSnVsLTIwMjc8L3RkPjx0ZD4xNC1KdWwtMjAyODwvdGQ+PHRkPlRFU1QtUkVQTEFDRU1FTlQ8L3RkPjwvdHI+PC90YWJsZT48L2h0bWw+"
    }
  ],
  "bom_rows": [
    {
      "row_id": "001",
      "manufacturer": "NXP",
      "mpn": "TEST001-A",
      "product_id": "SYNTHETIC-A",
      "revision": "001",
      "part_scope": "standard"
    },
    {
      "row_id": "002",
      "manufacturer": "NXP",
      "mpn": "TEST001-A",
      "product_id": "SYNTHETIC-B",
      "revision": "002",
      "part_scope": "standard"
    },
    {
      "row_id": "003",
      "manufacturer": "NXP",
      "mpn": "TEST001-B",
      "product_id": "SYNTHETIC-A",
      "revision": "001",
      "part_scope": "standard"
    }
  ],
  "synthetic_bom": true
}
```

# Actor output Schema

## `results` (type: `string`):

Default Dataset, one record per processed notice × BOM row. Retrieve all pages.

## `summary` (type: `string`):

Full results, notice and acquisition status, revision deltas and billing.

## `all_rows_csv` (type: `string`):

No description

## `impacts_csv` (type: `string`):

Includes inactive historical matches: check notice_active.

## `reviews_csv` (type: `string`):

manual_review and failed records; partial matched rows remain in impacts.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "documents": [
        {
            "notice_id": "202607010DN",
            "manufacturer": "NXP",
            "input_notice_ref": "synthetic-cloud-pipeline",
            "content_base64": "PGh0bWw+PGgxPjIwMjYwNzAxMEROIDogU3ludGhldGljIGV2YWx1YXRpb24gbm90aWNlPC9oMT48dGFibGU+PHRyPjx0aD5QQ04gVHlwZTwvdGg+PHRoPklzc3VlIERhdGU8L3RoPjx0aD5FZmZlY3RpdmUgRGF0ZTwvdGg+PC90cj48dHI+PHRkPkRpc2NvbnRpbnVhdGlvbiBOb3RpZmljYXRpb248L3RkPjx0ZD4xNC1KdWwtMjAyNjwvdGQ+PHRkPjE1LUp1bC0yMDI2PC90ZD48L3RyPjwvdGFibGU+PHRhYmxlPjx0cj48dGg+UGFydCBOdW1iZXIgLyAxMk5DPC90aD48dGg+RGlzY29udGludWF0aW9uIFR5cGU8L3RoPjx0aD5BdmFpbGFiaWxpdHk8L3RoPjx0aD5Tb3VyY2U8L3RoPjx0aD5MYXN0IFRpbWUgQnV5IERhdGU8L3RoPjx0aD5MYXN0IFRpbWUgRGVsaXZlcnkgRGF0ZTwvdGg+PHRoPlJlcGxhY2VtZW50IFBhcnQ8L3RoPjwvdHI+PHRyPjx0ZD5URVNUMDAxLUEgKDEyMzQ1Njc4OTAxMik8L3RkPjx0ZD5GVUxMIFdJVEhEUkFXQUw8L3RkPjx0ZD5MaW1pdGVkIEF2YWlsYWJpbGl0eTwvdGQ+PHRkPlNvbGUgU291cmNlPC90ZD48dGQ+MTQtSnVsLTIwMjc8L3RkPjx0ZD4xNC1KdWwtMjAyODwvdGQ+PHRkPlRFU1QtUkVQTEFDRU1FTlQ8L3RkPjwvdHI+PC90YWJsZT48L2h0bWw+"
        }
    ],
    "bom_rows": [
        {
            "row_id": "001",
            "manufacturer": "NXP",
            "mpn": "TEST001-A",
            "product_id": "SYNTHETIC-A",
            "revision": "001",
            "part_scope": "standard"
        },
        {
            "row_id": "002",
            "manufacturer": "NXP",
            "mpn": "TEST001-A",
            "product_id": "SYNTHETIC-B",
            "revision": "002",
            "part_scope": "standard"
        },
        {
            "row_id": "003",
            "manufacturer": "NXP",
            "mpn": "TEST001-B",
            "product_id": "SYNTHETIC-A",
            "revision": "001",
            "part_scope": "standard"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("amycole/pcn-to-bom-impact-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "documents": [{
            "notice_id": "202607010DN",
            "manufacturer": "NXP",
            "input_notice_ref": "synthetic-cloud-pipeline",
            "content_base64": "PGh0bWw+PGgxPjIwMjYwNzAxMEROIDogU3ludGhldGljIGV2YWx1YXRpb24gbm90aWNlPC9oMT48dGFibGU+PHRyPjx0aD5QQ04gVHlwZTwvdGg+PHRoPklzc3VlIERhdGU8L3RoPjx0aD5FZmZlY3RpdmUgRGF0ZTwvdGg+PC90cj48dHI+PHRkPkRpc2NvbnRpbnVhdGlvbiBOb3RpZmljYXRpb248L3RkPjx0ZD4xNC1KdWwtMjAyNjwvdGQ+PHRkPjE1LUp1bC0yMDI2PC90ZD48L3RyPjwvdGFibGU+PHRhYmxlPjx0cj48dGg+UGFydCBOdW1iZXIgLyAxMk5DPC90aD48dGg+RGlzY29udGludWF0aW9uIFR5cGU8L3RoPjx0aD5BdmFpbGFiaWxpdHk8L3RoPjx0aD5Tb3VyY2U8L3RoPjx0aD5MYXN0IFRpbWUgQnV5IERhdGU8L3RoPjx0aD5MYXN0IFRpbWUgRGVsaXZlcnkgRGF0ZTwvdGg+PHRoPlJlcGxhY2VtZW50IFBhcnQ8L3RoPjwvdHI+PHRyPjx0ZD5URVNUMDAxLUEgKDEyMzQ1Njc4OTAxMik8L3RkPjx0ZD5GVUxMIFdJVEhEUkFXQUw8L3RkPjx0ZD5MaW1pdGVkIEF2YWlsYWJpbGl0eTwvdGQ+PHRkPlNvbGUgU291cmNlPC90ZD48dGQ+MTQtSnVsLTIwMjc8L3RkPjx0ZD4xNC1KdWwtMjAyODwvdGQ+PHRkPlRFU1QtUkVQTEFDRU1FTlQ8L3RkPjwvdHI+PC90YWJsZT48L2h0bWw+",
        }],
    "bom_rows": [
        {
            "row_id": "001",
            "manufacturer": "NXP",
            "mpn": "TEST001-A",
            "product_id": "SYNTHETIC-A",
            "revision": "001",
            "part_scope": "standard",
        },
        {
            "row_id": "002",
            "manufacturer": "NXP",
            "mpn": "TEST001-A",
            "product_id": "SYNTHETIC-B",
            "revision": "002",
            "part_scope": "standard",
        },
        {
            "row_id": "003",
            "manufacturer": "NXP",
            "mpn": "TEST001-B",
            "product_id": "SYNTHETIC-A",
            "revision": "001",
            "part_scope": "standard",
        },
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("amycole/pcn-to-bom-impact-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "documents": [
    {
      "notice_id": "202607010DN",
      "manufacturer": "NXP",
      "input_notice_ref": "synthetic-cloud-pipeline",
      "content_base64": "PGh0bWw+PGgxPjIwMjYwNzAxMEROIDogU3ludGhldGljIGV2YWx1YXRpb24gbm90aWNlPC9oMT48dGFibGU+PHRyPjx0aD5QQ04gVHlwZTwvdGg+PHRoPklzc3VlIERhdGU8L3RoPjx0aD5FZmZlY3RpdmUgRGF0ZTwvdGg+PC90cj48dHI+PHRkPkRpc2NvbnRpbnVhdGlvbiBOb3RpZmljYXRpb248L3RkPjx0ZD4xNC1KdWwtMjAyNjwvdGQ+PHRkPjE1LUp1bC0yMDI2PC90ZD48L3RyPjwvdGFibGU+PHRhYmxlPjx0cj48dGg+UGFydCBOdW1iZXIgLyAxMk5DPC90aD48dGg+RGlzY29udGludWF0aW9uIFR5cGU8L3RoPjx0aD5BdmFpbGFiaWxpdHk8L3RoPjx0aD5Tb3VyY2U8L3RoPjx0aD5MYXN0IFRpbWUgQnV5IERhdGU8L3RoPjx0aD5MYXN0IFRpbWUgRGVsaXZlcnkgRGF0ZTwvdGg+PHRoPlJlcGxhY2VtZW50IFBhcnQ8L3RoPjwvdHI+PHRyPjx0ZD5URVNUMDAxLUEgKDEyMzQ1Njc4OTAxMik8L3RkPjx0ZD5GVUxMIFdJVEhEUkFXQUw8L3RkPjx0ZD5MaW1pdGVkIEF2YWlsYWJpbGl0eTwvdGQ+PHRkPlNvbGUgU291cmNlPC90ZD48dGQ+MTQtSnVsLTIwMjc8L3RkPjx0ZD4xNC1KdWwtMjAyODwvdGQ+PHRkPlRFU1QtUkVQTEFDRU1FTlQ8L3RkPjwvdHI+PC90YWJsZT48L2h0bWw+"
    }
  ],
  "bom_rows": [
    {
      "row_id": "001",
      "manufacturer": "NXP",
      "mpn": "TEST001-A",
      "product_id": "SYNTHETIC-A",
      "revision": "001",
      "part_scope": "standard"
    },
    {
      "row_id": "002",
      "manufacturer": "NXP",
      "mpn": "TEST001-A",
      "product_id": "SYNTHETIC-B",
      "revision": "002",
      "part_scope": "standard"
    },
    {
      "row_id": "003",
      "manufacturer": "NXP",
      "mpn": "TEST001-B",
      "product_id": "SYNTHETIC-A",
      "revision": "001",
      "part_scope": "standard"
    }
  ]
}' |
apify call amycole/pcn-to-bom-impact-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,amycole/pcn-to-bom-impact-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jxAaJZ8Wou3M1OoTc/builds/ZNMMEElHRAe0AVqGf/openapi.json
