# Supplier Below Cost Review (`remarkable_whipscorpion/supplier-below-cost-review`) Actor

Compare supplied supplier unit costs and store selling prices by exact SKU, with exact decimal differences and explicit unknown or ambiguous rows.

- **URL**: https://apify.com/remarkable_whipscorpion/supplier-below-cost-review.md
- **Developed by:** [Kagerou AP](https://apify.com/remarkable_whipscorpion) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / below-cost review completed

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 Below Cost Review

Find store selling prices below your supplied supplier unit costs. Paste two CSV exports, declare the headers and common price basis, and get exact SKU comparisons with source row references, coverage counts and explicit unknown or ambiguous results.

This Actor reviews the supplied export pair. It does not fetch supplier data, connect to a store or change selling prices.

### Try the original demo

The default input and Console prefill are the same useful, original synthetic demo:

```json
{ "mode": "demo" }
```

Demo mode accepts only `mode`; remove custom review fields before using it. It uses bundled CC0 data with supplier costs `8.10` for SKUs `001`, `002` and `003`, a missing cost for `004`, and store prices `7.90`, `8.10`, `12.00`, `9.00` and `3.00` for SKUs `001` through `005`. It reports one below-cost row, two not-below-cost rows and two unknown rows. The demo does not trigger the custom completion event. The platform start event still applies.

### Review your exports

This useful custom review sample uses the same invented data and triggers one completion event when the budget allows it:

```json
{
  "mode": "review",
  "supplierCsv": "sku,unit_cost\n001,8.10\n002,8.10\n003,8.10\n004,\n",
  "storeCsv": "sku,price\n001,7.90\n002,8.10\n003,12.00\n004,9.00\n005,3.00\n",
  "supplierColumns": { "sku": "sku", "unitCost": "unit_cost" },
  "storeColumns": { "sku": "sku", "price": "price" },
  "currency": "USD",
  "comparableUnitAndTaxBasisConfirmed": true,
  "rightsConfirmed": true
}
```

Replace the CSV text with exports you are authorized to process. `rightsConfirmed` must be `true` for every custom review. Values are CSV contents, not URLs, paths or uploads. The Actor sends no data to a supplier, store or other external service; input and output are stored in your Apify run storage.

Column mappings are required in review mode. Declare the exact case-sensitive SKU and price headers in each export; for the sample these are `sku` / `unit_cost` for the supplier and `sku` / `price` for the store. Required header duplicates or mapping two required fields to the same header are invalid. No defaults or aliases are guessed.

Declare one uppercase three-letter `currency` for both columns and set `comparableUnitAndTaxBasisConfirmed` to `true` only when the prices use the same selling unit and tax basis. These are your assertions. The Actor cannot detect a hidden currency, pack-size or tax-basis difference. Missing or invalid currency, or a missing/false basis confirmation, produces diagnostics without price arithmetic or a custom completion event.

### Interpret the result

Matching uses exact case-sensitive string SKUs. Leading zeros and whitespace are preserved: `001`, `1`, `SKU001` and `sku001` are different identifiers. A SKU duplicated in either export is ambiguous; the Actor does not choose the lowest supplier cost or an arbitrary row.

| Row status | Meaning |
| --- | --- |
| `below_cost` | Store price minus matched supplier unit cost is negative. |
| `not_below_cost` | The exact difference is zero or positive. |
| `unknown` | No unique supplier match, missing/invalid price or another stated prerequisite prevents comparison. |
| `ambiguous` | Duplicate matching SKU rows prevent a unique comparison. |

`differenceExact` is **store selling price minus supplier unit cost**, in the declared common currency. A cost of `8.10` and price of `7.90` gives `-0.20`; `8.10` and `8.10` gives `0`; `8.10` and `12.00` gives `3.90`. Exact scaled-integer arithmetic avoids binary floating-point money errors. Missing or invalid prices stay unknown and are never estimated.

### Outputs

The run's Output tab links to three outputs:

- **Default Dataset:** one summary item with numeric `schemaVersion: 1`, overall `status`, `mode`, `useful`, `coverage`, `detailRows`, `detailCap`, output record keys and `billing`.
- **`REPORT.json` in the default key-value store:** the complete report with store-row results, declared currency, coverage counts, `unmatchedSupplierRows` and all mapped `sourceRecords`. Each result shows at most 20 supplier row references, with `supplierMatchCount` and `supplierRowsTruncated` exposing larger ambiguous groups; all source records remain available in JSON.
- **`REVIEW.csv` in the default key-value store:** store-row review results, prices, exact differences and reason codes. Formula-like spreadsheet cells are guarded. Use JSON when exact original cell strings matter.

Coverage includes supplier/store/output row totals, calculable, below-cost, not-below-cost, unknown and ambiguous rows, unmatched store rows, unused supplier rows and duplicate SKU counts. The detail cap is 5,000 store rows, equal to the input cap; over-limit CSVs are rejected rather than silently truncated. Unknown and ambiguous rows remain visible alongside useful comparisons. A useful pair with one valid row and two unknown rows produces one report and one custom completion event.

### Pricing and budget

The Pay-per-event completion price is **$0.25 for one useful completed export-pair review**, event `below_cost_review_completed`. Useful means at least one store row can be compared to a unique supplier row using valid prices and confirmed common basis. The price is per report, independent of the number of below-cost rows; there is no Dataset item event fee.

Original demo runs, rejected input and reviews with no calculable rows trigger **zero custom completion events**. Apify's platform-managed **$0.00005 start event applies even to demo and diagnostic runs**. Platform infrastructure charges, where applicable to your account, are separate.

Budget capacity for the complete $0.25 report event is checked before any useful Dataset, key-value store or checkpoint content is saved. The startup allocation is handled separately. A budget that cannot fund one complete review returns diagnostics without a useful partial report. Useful report outputs are persisted before the completion event is charged. A resumed run checks its saved state to avoid duplicate fees; an uncertain prior charge is left unconfirmed and is not blindly retried. Inspect `billing.state` and `billing.chargedCount` in **`REPORT.json` for authoritative confirmation**. The Dataset summary is saved before charging and can show `confirmation_in_REPORT.json` with `chargedCount: null` even after a confirmed charge.

### Limits and scope

- Maximum **5 MiB UTF-8, 5,000 data rows and 200 columns per CSV**. CSV headers and RFC 4180 quoting are supported.
- Prices must be nonnegative decimal strings, with at most **12 integer digits and 6 decimal places**. No exponent notation, thousands separators, currency symbols or currency conversion.
- No title, GTIN or fuzzy matching; no supplier SKU map, automatic header inference, tax/pack conversion or guessed prices.
- No landed-cost or net-profit calculation, shipping/tax/fee deductions, profitability claim, retail price recommendation, stock sync or automatic store update.

The result flags a supplied selling price below a supplied comparable unit cost. It does not establish profitability, a safe selling price, or whether either export is current or complete.

### Source and licenses

No external data source is fetched. Your exports provide the prices and identifiers. The original synthetic demo data is dedicated under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/). Product code is MIT licensed; see `LICENSE`. Dependencies are pinned to Apify SDK `3.7.2` (Apache-2.0) and `csv-parse` `7.0.2` (MIT).

Actor metadata follows the official [input schema](https://docs.apify.com/actors/development/actor-definition/input-schema/specification/v1), [Dataset schema](https://docs.apify.com/storage/dataset-schema) and [Actor output schema](https://docs.apify.com/actors/development/actor-definition/output-schema) formats. The container runs Node.js 24 with lockfile installation. Native build, platform schema recognition and live pricing configuration require release validation; a local source package alone does not confirm those platform states.

# Actor input Schema

## `mode` (type: `string`):

demo uses only the bundled original CC0 fixture and accepts no custom fields. review uses your CSV text and charges once if at least one price can be compared.

## `supplierCsv` (type: `string`):

Required in review mode. Paste CSV contents, including headers, rather than a URL or file path. Maximum 5 MiB UTF-8, 5,000 data rows and 200 columns. A SKU and unit-cost column are needed.

## `storeCsv` (type: `string`):

Required in review mode. Paste CSV contents, including headers, rather than a URL or file path. Maximum 5 MiB UTF-8, 5,000 data rows and 200 columns. A SKU and selling-price column are needed.

## `supplierColumns` (type: `object`):

Required in review mode: declare exact case-sensitive headers, for example {"sku":"sku","unitCost":"unit_cost"}. No header aliases or automatic column guessing.

## `storeColumns` (type: `object`):

Required in review mode: declare exact case-sensitive headers, for example {"sku":"sku","price":"price"}. No header aliases or automatic column guessing.

## `currency` (type: `string`):

In review mode, declare one uppercase three-letter currency such as USD for both price columns. This is your assertion; the Actor does not detect actual currency differences or convert currencies. Missing or invalid currency disables arithmetic and returns diagnostics.

## `comparableUnitAndTaxBasisConfirmed` (type: `boolean`):

Set true in review mode only after confirming supplier cost and store price use the same selling unit and tax basis. Missing or false disables arithmetic. The Actor does not infer units, pack sizes or tax treatment.

## `rightsConfirmed` (type: `boolean`):

Required as true in review mode: you own or are authorized to process both supplied exports. Missing or false rejects custom input. No data is fetched from suppliers or stores. The original demo fixture has its own CC0 permission.

## Actor input object example

```json
{
  "mode": "demo"
}
```

# Actor output Schema

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

Default Dataset summary with status, coverage counts and detail count. Custom billing confirmation is authoritative in REPORT.json; the saved summary can point there with chargedCount null. Row details are in the report and CSV.

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

REPORT.json contains the same summary facts, store-row review details, source row references and unmatched supplier rows. Check billing.state for confirmed or uncertain charge status.

## `reviewCsv` (type: `string`):

REVIEW.csv contains store-row results and exact decimal differences. Spreadsheet formula-like cells are guarded; use the JSON report to preserve exact original strings.

# 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 = {
    "mode": "demo"
};

// Run the Actor and wait for it to finish
const run = await client.actor("remarkable_whipscorpion/supplier-below-cost-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 = { "mode": "demo" }

# Run the Actor and wait for it to finish
run = client.actor("remarkable_whipscorpion/supplier-below-cost-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 '{
  "mode": "demo"
}' |
apify call remarkable_whipscorpion/supplier-below-cost-review --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,remarkable_whipscorpion/supplier-below-cost-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/kQvOoAQvU65zuppNx/builds/J68aAqEUmKHAQzoRz/openapi.json
