# Supplier Catalog Change Review (`jj_toolworks/supplier-catalog-change-review`) Actor

Compare supported supplier CSV snapshots to review added, absent, and changed products, including price and stock changes. Get JSON and CSV reports with validation evidence. Two fixed formats; USD; up to 10,000 rows per snapshot.

- **URL**: https://apify.com/jj_toolworks/supplier-catalog-change-review.md
- **Developed by:** [JJ Toolworks](https://apify.com/jj_toolworks) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / catalog comparison

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

## Supplier Catalog Change Review

Compare a previous supplier catalog with an incoming CSV and get a traceable
report of additions, absences, price changes, stock changes, and other field
changes. Invalid data is explained before it can produce a misleading comparison.

This initial release supports two explicit CSV formats. It is useful as a bounded
step in a catalog-processing workflow. It does not connect to a supplier account
or update a store.

### What you receive

- **Report JSON:** authoritative validation status, counts, record changes,
  source evidence, input hashes, and custom-event billing status.
- **Changes CSV:** a review table of the records that differ.
- **Exceptions CSV:** input problems and reasons a comparison was blocked.

All three files appear in the run's Output tab. Always inspect the JSON status:
an empty changes file can mean no changes, validation-only mode, or a blocked
comparison. It does not by itself establish that two catalogs match.

A successful validation-only run also writes one summary to the run's default
dataset: the profile, parsed and valid row counts, issue count, comparison status,
and keys for the detailed report files. This summary does not request a custom
comparison event. Comparison runs continue to deliver their results in the three
files above.

### Input

Choose a supported profile, paste the current CSV contents, and optionally paste
the previous CSV contents. API callers send the same values as JSON strings.
No file URL, account credential, local path, or custom executable configuration
is needed or accepted.

For comparison, confirm that both files are complete snapshots of the same
catalog scope. The tool cannot independently discover whether an export omitted
otherwise valid rows or verify which snapshot was captured earlier.

| Field | Meaning |
|---|---|
| `profileId` | `generic_catalog` (default) or `synthetic_building_materials` |
| `currentCsv` | Required inline CSV text, including its header |
| `baselineCsv` | Optional previous full CSV; omit the field for validation only |
| `snapshotScopeConfirmed` | Must be `true` when a baseline is supplied |

#### Generic format

```csv
sku,name,price,stock,currency
001,Example item,10.00,25,USD
002,Another item,12.50,8,USD
```

Every listed column and row value is required. SKU is exact, case-sensitive text;
leading zeros are preserved. Price is a nonnegative decimal with at most two
places; stock is a nonnegative integer; currency must be `USD`.

#### Synthetic building-materials format

```csv
Supplier Code,Item Code,Description,Sell Unit,Unit Price,Available Units,Currency
SUP-A,ITEM-001,Example material,each,10.00,25,USD
```

The exact supplier code plus item code identify a record. Both are required.
The optional extra column `Internal Note` is deliberately ignored. The sell-unit
field provides price context: a unit change prevents an incomparable price delta.
This profile is an example schema, not verified compatibility with a named vendor.

### Interpretation and limits

Identifiers are never guessed, trimmed, case-folded, or fuzzily matched. Duplicate
identifiers, invalid values, malformed CSV, unexpected columns, or incomplete
reads block the entire comparison. The output explains the problem and returns
null comparison counts rather than misleading zeros.

An item marked `removed` is **absent from the supplied valid snapshot**. It is not
a destination deletion instruction or proof that a supplier discontinued it.
Changed identifiers appear as an addition and an absence.

Each snapshot is limited to **2,000,000 UTF-8 bytes and 10,000 data rows**. Headers
must match exactly. The profiles reject empty snapshots, price rounding,
thousands separators, currency symbols, exponent notation, negative stock, and
unknown currency codes. No currency or unit conversion is performed.

CSV review files neutralize formula-leading cells. JSON retains the original
relevant values and represents decimal amounts as strings to preserve precision.

### Pricing behavior

The proposed sale unit is one completed, valid comparison. The actual price is
the event price displayed by Apify. The custom event is requested only after the
report and review files have been stored.

Validation-only reports and invalid inputs do not trigger the custom comparison
event. Total platform charges depend on the published pricing configuration.
The intended release configuration contains only `catalog-comparison`, with no
automatic startup or dataset charge and no passed-through usage charge.

A spending limit must cover one event. A fresh run is a new execution, even if it
uses identical input. Within a resumed run, recorded completed work is reused.
If a charge response is ambiguous, automatic charging stops for review.

### Data handling

The tool processes the CSV in an isolated temporary directory and removes those
temporary files when processing ends. Inputs and result artifacts also exist in
Apify run storage and follow that account's retention and deletion settings.
Delete the run's input and output storage when it is no longer needed. This
package does not configure an account-wide retention policy or automatically
delete stored run results. Routine application status messages contain summaries,
not CSV contents.

### Scope

This tool produces review information. It does not submit imports, change prices
or inventory, verify external product identity, or determine why stock changed.
Use a new run for each new pair of snapshots.

# Actor input Schema

## `profileId` (type: `string`):

Choose the exact supported column format. Both bundled formats are documented examples, not live vendor integrations.

## `currentCsv` (type: `string`):

UTF-8 CSV contents including headers. Maximum 2,000,000 UTF-8 bytes and 10,000 data rows. JSON input is also supported through the Actor API.

## `baselineCsv` (type: `string`):

Omit this field for validation only. If supplied, it must be a complete snapshot of the same scope with matching headers. Maximum 2,000,000 UTF-8 bytes and 10,000 data rows.

## `snapshotScopeConfirmed` (type: `boolean`):

Required to compare snapshots. Absence from a file means only absence from that snapshot; it does not prove discontinuation or authorize deletion.

## Actor input object example

```json
{
  "profileId": "generic_catalog",
  "currentCsv": "sku,name,price,stock,currency\n001,Example fastener pack,13.00,35,USD\n002,Example sealant,8.00,12,USD\n004,Example bracket revised,3.25,100,USD\n005,Example flashing,18.50,8,USD\n",
  "snapshotScopeConfirmed": false
}
```

# Actor output Schema

## `report` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `exceptions` (type: `string`):

No description

# 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 = {
    "currentCsv": `sku,name,price,stock,currency
001,Example fastener pack,13.00,35,USD
002,Example sealant,8.00,12,USD
004,Example bracket revised,3.25,100,USD
005,Example flashing,18.50,8,USD`
};

// Run the Actor and wait for it to finish
const run = await client.actor("jj_toolworks/supplier-catalog-change-review").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 = { "currentCsv": """sku,name,price,stock,currency
001,Example fastener pack,13.00,35,USD
002,Example sealant,8.00,12,USD
004,Example bracket revised,3.25,100,USD
005,Example flashing,18.50,8,USD
""" }

# Run the Actor and wait for it to finish
run = client.actor("jj_toolworks/supplier-catalog-change-review").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 '{
  "currentCsv": "sku,name,price,stock,currency\\n001,Example fastener pack,13.00,35,USD\\n002,Example sealant,8.00,12,USD\\n004,Example bracket revised,3.25,100,USD\\n005,Example flashing,18.50,8,USD\\n"
}' |
apify call jj_toolworks/supplier-catalog-change-review --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jj_toolworks/supplier-catalog-change-review"
        }
    }
}
```

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/Xk6OnxZPmuGRcpDoI/builds/Dwect3wU8aNEh6WxV/openapi.json
