# Amazon Discount Data Audit (Offline Dataset Checker) (`practical_ai_lab_jp/pal-amazon-discount-data-audit`) Actor

Check discount claims against list and current prices in your authorized Amazon offer dataset. Flag wrong percentages, implausible promotions and currency issues, with reviewable item-level evidence. No Amazon scraping.

- **URL**: https://apify.com/practical_ai_lab_jp/pal-amazon-discount-data-audit.md
- **Developed by:** [Practical AI Lab](https://apify.com/practical_ai_lab_jp) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 audited offers

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

## Amazon Discount Data Audit

Checks whether the discount claims in your **existing** Amazon offer data are supported by the list and current prices in the same rows, and flags implausible claims. It works only on data you supply. It does not visit Amazon, fetch prices, log in, or use proxies.

### What it does

For each row it compares the claimed discount (percent and/or savings amount) with the discount computed from the list price and current price, then assigns a verdict:

| Verdict | Meaning |
| --- | --- |
| `supported` | Claim matches the arithmetic within your tolerance |
| `unsupported` | Claim does not match the prices (percent and/or amount gap) |
| `implausible` | Inverted prices, zero or negative price, claim of 100% or more, or a discount above your plausibility limit |
| `no_claim` | Prices present, but no discount claim to verify |
| `incomplete` | Missing, unparseable or mixed-currency data, so no arithmetic verdict was possible |

Each row also gets machine-readable `flags` (for example `PERCENT_MISMATCH`, `AMOUNT_MISMATCH`, `EXTREME_DISCOUNT`, `INVERTED_PRICES`, `CONFLICTING_DUPLICATE`, `CURRENCY_MISMATCH`) and a 0-100 `severity` score for sorting. A `SUMMARY` record in the key-value store gives verdict counts, flag counts, the problem rate and sample-size notes.

Price parsing handles `$1,299.99`, `1.299,99 €`, plain numbers and nested objects such as `{"value": "19.99", "currency": "GBP"}`.

### Sample input

```json
{
  "items": [
    {"asin": "B0SAMPLE01", "title": "Sample kettle", "listPrice": "$100.00", "price": "$75.00", "discount": "25%"},
    {"asin": "B0SAMPLE02", "title": "Sample headphones", "listPrice": "$80.00", "price": "$60.00", "discount": "40%"},
    {"asin": "B0SAMPLE03", "title": "Sample cable", "listPrice": "$10.00", "price": "$12.00", "discount": "20%"},
    {"asin": "B0SAMPLE04", "title": "Sample lamp", "listPrice": "$1,000.00", "price": "$50.00", "discount": "95%"},
    {"asin": "B0SAMPLE05", "title": "Sample mug", "price": "$8.00", "discount": "30%"}
  ],
  "percentTolerance": "1.0",
  "maxPlausiblePercent": "90"
}
```

Expected behavior for this sample: row 1 is supported, row 2 is unsupported (computed 25%, claimed 40%), row 3 is implausible (list price below current price), row 4 is implausible (95% exceeds the limit), and row 5 is incomplete (no list price).

### Input

- `items`: array of offer objects. Default field names are detected automatically (`asin`/`id`, `title`, `listPrice`/`originalPrice`, `price`/`salePrice`, `discount`/`discountPercent`, `savings`, `currency`).
- `sourceDatasetId`: optional ID of an Apify dataset in your own account; rows are read after inline items.
- `fieldMap`: rename fields, with dotted paths allowed, e.g. `{"listPrice": "pricing.was", "currentPrice": "pricing.now"}`.
- `percentTolerance`, `amountTolerance`: rounding allowances.
- `maxPlausiblePercent`: discounts above this are flagged even when arithmetic matches.
- `maxItems`: row cap (hard limit 50,000). `onlyFlagged`: write only problem rows to the dataset.

### Output

One dataset row per input row: `sourceIndex`, `id`, `title`, `listPrice`, `currentPrice`, `currency`, `claimedPercent`, `claimedAmount`, `computedPercent`, `computedAmount`, `percentDifference`, `verdict`, `flags`, `severity`.

### Pricing model

The Actor is written to emit one `audited-offer` event per row that received an arithmetic verdict. Rows that are `incomplete`, invalid input, and failed runs are not charged. The event is only charged after the row has been written to the dataset. Pricing availability depends on how the Actor is configured on the platform.

### Limitations

- It verifies internal arithmetic consistency only. A row can be consistent and still wrong, because the Actor cannot confirm real Amazon prices, coupons, or the history behind a "list price".
- A list price that looks inflated cannot be detected without price history, which this Actor does not use. The plausibility limit is a heuristic you set, not a rule.
- Ambiguous number formats are guessed: `1,234` is read as 1234 and `12,5` as 12.5; `1.234` is read as 1.234. Use `fieldMap` plus clean numbers if your data is unusual.
- A bare number in a percent field is read as a percent (0.25 means 0.25%, not 25%).
- Rows with several currencies are marked incomplete rather than converted.
- Duplicate detection is by ID within one run and compares only list and current prices.
- Small samples (under 30 auditable rows) give problem rates that are not statistically meaningful; the summary says so.
- Results depend entirely on the quality and freshness of the data you provide. You are responsible for having the right to process it.

### Development

Tests are offline: `python -m unittest discover -s tests`.

# Actor input Schema

## `items` (type: `array`):

Existing offer records (JSON objects). Common fields are detected automatically: asin, title, listPrice, price, discount, savings, currency. Nothing is fetched from Amazon.

## `sourceDatasetId` (type: `string`):

ID of an existing Apify dataset in your account holding offer rows. Rows are read after inline items.

## `fieldMap` (type: `object`):

Override field names. Keys: id, title, listPrice, currentPrice, claimedPercent, claimedAmount, currency. Dotted paths such as pricing.list are allowed.

## `percentTolerance` (type: `string`):

Allowed gap between claimed and computed discount percent, to absorb rounding. Range 0 to 20.

## `amountTolerance` (type: `string`):

Allowed gap between a claimed savings amount and list minus current price. Range 0 to 100.

## `maxPlausiblePercent` (type: `string`):

Discounts above this level are marked implausible even when arithmetic matches. Range 10 to 100.

## `maxItems` (type: `integer`):

Upper bound on rows processed (hard cap 50000).

## `onlyFlagged` (type: `boolean`):

Skip supported and no-claim rows in the dataset. The summary still counts them. Only pushed rows are billed.

## Actor input object example

```json
{
  "items": [
    {
      "asin": "B0SAMPLE01",
      "title": "Sample kettle",
      "listPrice": "$100.00",
      "price": "$75.00",
      "discount": "25%"
    },
    {
      "asin": "B0SAMPLE02",
      "title": "Sample headphones",
      "listPrice": "$80.00",
      "price": "$60.00",
      "discount": "40%"
    },
    {
      "asin": "B0SAMPLE03",
      "title": "Sample cable",
      "listPrice": "$10.00",
      "price": "$12.00",
      "discount": "20%"
    },
    {
      "asin": "B0SAMPLE04",
      "title": "Sample lamp",
      "listPrice": "$1,000.00",
      "price": "$50.00",
      "discount": "95%"
    },
    {
      "asin": "B0SAMPLE05",
      "title": "Sample mug",
      "price": "$8.00",
      "discount": "30%"
    }
  ],
  "percentTolerance": "1.0",
  "amountTolerance": "0.02",
  "maxPlausiblePercent": "90",
  "maxItems": 1000,
  "onlyFlagged": false
}
```

# Actor output Schema

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

Download rows from the latest run in JSON/CSV.

# 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 = {
    "items": [
        {
            "asin": "B0SAMPLE01",
            "title": "Sample kettle",
            "listPrice": "$100.00",
            "price": "$75.00",
            "discount": "25%"
        },
        {
            "asin": "B0SAMPLE02",
            "title": "Sample headphones",
            "listPrice": "$80.00",
            "price": "$60.00",
            "discount": "40%"
        },
        {
            "asin": "B0SAMPLE03",
            "title": "Sample cable",
            "listPrice": "$10.00",
            "price": "$12.00",
            "discount": "20%"
        },
        {
            "asin": "B0SAMPLE04",
            "title": "Sample lamp",
            "listPrice": "$1,000.00",
            "price": "$50.00",
            "discount": "95%"
        },
        {
            "asin": "B0SAMPLE05",
            "title": "Sample mug",
            "price": "$8.00",
            "discount": "30%"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("practical_ai_lab_jp/pal-amazon-discount-data-audit").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 = { "items": [
        {
            "asin": "B0SAMPLE01",
            "title": "Sample kettle",
            "listPrice": "$100.00",
            "price": "$75.00",
            "discount": "25%",
        },
        {
            "asin": "B0SAMPLE02",
            "title": "Sample headphones",
            "listPrice": "$80.00",
            "price": "$60.00",
            "discount": "40%",
        },
        {
            "asin": "B0SAMPLE03",
            "title": "Sample cable",
            "listPrice": "$10.00",
            "price": "$12.00",
            "discount": "20%",
        },
        {
            "asin": "B0SAMPLE04",
            "title": "Sample lamp",
            "listPrice": "$1,000.00",
            "price": "$50.00",
            "discount": "95%",
        },
        {
            "asin": "B0SAMPLE05",
            "title": "Sample mug",
            "price": "$8.00",
            "discount": "30%",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("practical_ai_lab_jp/pal-amazon-discount-data-audit").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 '{
  "items": [
    {
      "asin": "B0SAMPLE01",
      "title": "Sample kettle",
      "listPrice": "$100.00",
      "price": "$75.00",
      "discount": "25%"
    },
    {
      "asin": "B0SAMPLE02",
      "title": "Sample headphones",
      "listPrice": "$80.00",
      "price": "$60.00",
      "discount": "40%"
    },
    {
      "asin": "B0SAMPLE03",
      "title": "Sample cable",
      "listPrice": "$10.00",
      "price": "$12.00",
      "discount": "20%"
    },
    {
      "asin": "B0SAMPLE04",
      "title": "Sample lamp",
      "listPrice": "$1,000.00",
      "price": "$50.00",
      "discount": "95%"
    },
    {
      "asin": "B0SAMPLE05",
      "title": "Sample mug",
      "price": "$8.00",
      "discount": "30%"
    }
  ]
}' |
apify call practical_ai_lab_jp/pal-amazon-discount-data-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,practical_ai_lab_jp/pal-amazon-discount-data-audit"
        }
    }
}
```

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/JBFJcAUWKmesPFuQv/builds/lDdjfNSgpUZ96HgI6/openapi.json
