# MAP Price Violation Monitor & Alerts (`lowlanddata/map-price-violation-monitor`) Actor

Monitor your product list across retailer sites and get alerted the moment a price drops below your MAP (minimum advertised price). Stateful: alerts only on new violations, deeper cuts and recoveries — never repeats. Works on Shopify, WooCommerce, BigCommerce, Magento and custom shops. GDPR-clean.

- **URL**: https://apify.com/lowlanddata/map-price-violation-monitor.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 baseline price snapshots

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## MAP Price Violation Monitor & Alerts

Watch your product list across retailer websites and get an alert the moment a
retailer advertises below your MAP (minimum advertised price) — plus the deeper
cuts and the recoveries. The monitor remembers what it has already told you, so an
alert always means **something changed**, never "still broken, billed again."

It reads prices the way Google does — from the shops' own structured data — so it
works across thousands of independent web shops (Shopify, WooCommerce, BigCommerce,
Magento, custom platforms) without per-site parsers. Output is strictly product and
price data: no shop-owner names, no contact details, nothing personal — safe to
store, share with your legal team, or feed into enforcement letters.

### Quick start (30 seconds)

1. Open the actor and press **Start** — the prefilled demo list (3 real products
   with demo MAP values) runs in a few seconds and shows you a baseline snapshot,
   including one MAP violation.
2. Replace the demo list with your products: one `{ "url", "mapPrice" }` pair per
   retailer product page (paste your price list into the AI prompt below if you
   don't want to write JSON).
3. Add a **daily schedule** (Actor page → Schedule). From then on, runs are quiet
   until a price actually crosses your MAP.

### Who uses this

- **A consumer-electronics brand** with 40 authorized dealers lists each dealer's
  product page for its 12 SKUs. Tuesday 9:00, one dealer starts a "-15%" promo that
  goes under MAP on three SKUs — three alert items appear with the exact advertised
  price and depth (`deltaPct: -14.97`), ready to paste into the enforcement email.
- **A supplement brand** watches 200 web-shop listings of its range. Most runs cost
  a fraction of a cent and stay empty; the run after a rogue discounter cut prices
  contains exactly the new violations, nothing it already reported yesterday.
- **A sports-gear distributor** enforces reseller agreements across independent
  dealer shops in three countries, one monitor per country (state stores keep them
  separate), each with the currency of that market — a euro price is never compared
  against a dollar MAP.
- **An agency running MAP programs** for client brands schedules one monitor per
  client and exports the violation history per quarter as evidence of enforcement.

### What you get

One JSON item per **event**: a baseline snapshot per product on the first run, then
only transitions — new violation, deeper cut, recovery, or a page that stopped being
readable. A violation item looks like:

```json
{
  "productUrl": "https://dealer-shop.example.com/products/pro-widget-2000",
  "label": "Pro Widget 2000",
  "retailer": "dealer-shop.example.com",
  "productName": "Pro Widget 2000 — Stainless",
  "status": "violation",
  "isViolation": true,
  "isBaseline": false,
  "isUpdate": true,
  "advertisedPrice": 84.99,
  "priceHigh": null,
  "priceIsVariantLow": false,
  "currency": "USD",
  "currencyVerified": true,
  "mapPrice": 99.95,
  "deltaAbs": -14.96,
  "deltaPct": -14.97,
  "availability": "in-stock",
  "priceSource": "json-ld",
  "checkedAt": "2026-07-16T06:30:12.000Z",
  "note": null
}
````

Field honesty notes:

- `advertisedPrice` is what a shopper sees on the page **now** — on sale pages the
  sale price, never the crossed-out list price. For multi-variant products it is the
  cheapest advertised variant (`priceIsVariantLow: true`, range top in `priceHigh`).
- `currencyVerified: false` means the page did not state an unambiguous currency
  (e.g. a bare `$`) and your input currency was assumed. A page that clearly
  advertises a *different* currency is never compared — it becomes an uncharged
  `currency-mismatch` item instead.
- `priceSource` tells you which extraction path read the price; `json-ld` (the
  shops' own Google-facing structured data) is the most reliable.
- When a page can't be read with confidence, you get `status: "unreadable"` or
  `"unreachable"` — reported once per change, never charged, never guessed.

### Pricing

Pay per outcome — checking your whole catalog costs nothing; you pay when the
monitor tells you something new:

- **MAP violation alert (new violation or deeper cut): $0.10**
- Price recovered alert (optional, `alertOn`): $0.02
- Baseline snapshot item (first check of a product): $0.002
- Actor start: $0.0001. Platform usage (a few cents per run) is billed by Apify.

Cost feel: monitoring 100 products daily costs $0.20 once for the baseline, then
roughly **$0.50–2/month** at typical violation rates — a quiet month is nearly
free. Dedicated MAP software subscriptions for the same job run $50–500/month.

#### Why an alert costs more than a scraped row

The store's headline ("from $2.00 / 1,000 baseline price snapshots") is what a trial
costs: 500 products baselined = $1. Apify displays every event per 1,000, so in the
pricing table the violation alert reads "$100 / 1,000" next to price scrapers at
$1–3 per 1,000 rows — but that comparison is between different things:

- A **raw price scraper** sells rows: re-download all 100 products every day
  (3,000 rows/month), then build your own diffing, state and MAP logic on top.
- A **stateless checker** re-flags every known violation every run — on day 30 you
  have paid 30 times for the same broken price, and your inbox filter, not the
  tool, decides what is new.
- **This monitor** sells the transition: it remembers every product's last known
  state and charges $0.10 exactly when a retailer newly crosses your MAP or cuts
  deeper. Nobody buys 1,000 alerts a month — if you did, you'd have bigger
  problems than tooling costs.

### Not technical? Let your AI assistant set it up

Paste this into ChatGPT, Claude, or any assistant, together with your price list
(a pasted spreadsheet, CSV, or even "product page links plus the minimum prices"):

```text
Convert my price list into the JSON input for the Apify actor
"MAP Price Violation Monitor & Alerts" (lowlanddata/map-price-violation-monitor)
and tell me exactly where to paste it.

Rules for the input:
- The input field "products" is a JSON array; one object per retailer product
  page: { "url": "<full product page URL>", "mapPrice": <number>,
  "currency": "<ISO code like USD or EUR, default USD>",
  "label": "<short name I'll recognize>" }.
- One entry per RETAILER PAGE: if 3 shops sell the same product, that is 3
  entries with the same label and mapPrice but different urls.
- Other fields I might set: alertOn ("violations" or
  "violations-and-recoveries"), maxItems (default 500). Leave emitBaseline,
  resetState and stateStoreName at their defaults.
- Then tell me how to add a daily schedule on Apify so I get alerts
  automatically, and how to add an email notification when a run pushes items.

Here is my price list:
[PASTE YOUR LIST / SPREADSHEET COLUMNS HERE]
```

***

### Coverage — measured, not promised

The extractor was validated against a live sample of real shops across the platform
families (July 2026): the shops' own structured data (JSON-LD) reads a correct
price on about **60%** of long-tail shops; with the platform fallbacks
(Shopify product JSON, price metas, WooCommerce core markup) coverage reached
**14 of 15** sampled shops. What that means in practice:

- **Works:** independent and mid-size web shops — Shopify (incl. headless),
  WooCommerce, BigCommerce, Magento and custom storefronts that publish price
  structured data for Google (most do; it's how they get rich results).
- **Not covered in v1 — by design, stated honestly:**
  - **Amazon, Walmart, Home Depot and similar marketplaces/big-box sites.** They
    publish no structured price data and/or actively block automated access. We
    don't play cat-and-mouse with bot walls.
  - **Shops that render prices only in JavaScript** (no structured data in the
    HTML). These produce `unreadable` items — uncharged.
  - **Login-walled or challenge-walled pages** — `unreachable`, uncharged.
- A page the monitor cannot read with confidence is **never guessed and never
  charged** — precision beats recall when every alert is a billed event.
- **Regional pricing:** many shops price by visitor location. Set the proxy
  country (Input → Proxy → country) to the market whose advertised price you are
  enforcing, e.g. US for a USD MAP list.

### How the monitor thinks

- **First run = baseline.** Every product is checked and pushed once as
  `isBaseline: true` (violating or not) at the cheap baseline price, seeding the
  monitor's memory. A first-sight product whose page could not be read still gets
  its baseline row — uncharged, like every problem item. Turn `emitBaseline` off
  to seed silently.
- **After that, only transitions.** An unchanged violation never re-alerts. A
  violation alerts again only when the price cuts *deeper*. A price that rises but
  stays below MAP stays silent (still a violation, not news).
- **Recoveries** (violating → back at/above MAP) alert only with
  `alertOn: "violations-and-recoveries"`, at the lower recovery price.
- **Editing the list is safe:** adding a product baselines only that product;
  removing one just stops checking it. Changing a product's `mapPrice` re-evaluates
  it against the new MAP — if the standing price is below the new MAP, that alerts
  as a new violation.
- **Memory** lives in a named key-value store (`stateStoreName`, default
  `map-monitor-state`) in your account. One monitor per store: give each brand,
  market or client its own store name. `resetState: true` wipes it for a fresh
  baseline.
- Re-running after a crash or overlap re-alerts at most the last few unsaved
  items — state is checkpointed during the run.

### Input reference

| Field                | Type    | Default             | Notes                                                                                       |
| -------------------- | ------- | ------------------- | ------------------------------------------------------------------------------------------- |
| `products`           | array   | 3 demo products     | 1–500 entries: `url`, `mapPrice`, optional `currency` (ISO, default USD), optional `label`. |
| `alertOn`            | enum    | `violations`        | `violations` or `violations-and-recoveries`.                                                |
| `emitBaseline`       | boolean | `true`              | Push first-sight snapshots; off = silent seeding.                                           |
| `resetState`         | boolean | `false`             | Forget everything; next run is a full baseline.                                             |
| `maxItems`           | integer | `500`               | Per-run push cap. Alerts are pushed before baselines; overflow alerts on the next run.      |
| `stateStoreName`     | string  | `map-monitor-state` | Key-value store holding monitor memory; one per independent monitor.                        |
| `proxyConfiguration` | object  | Apify datacenter    | Set a country to read region-specific prices.                                               |

Duplicate URLs are checked once (first entry wins). ~1 page fetch per product,
politely paced per shop: 100 products finish in well under a minute.

### Scheduling and API use

The monitor is built to run on a schedule (daily is typical; hourly for launch
weeks). In Console: Actor page → **Schedules**. Get alerted only when something
happened: Actor page → **Monitoring** → notify when *dataset items > 0*.

Run it from code and get the items back in one call:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/lowlanddata~map-price-violation-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"products": [{"url": "https://dealer-shop.example.com/products/pro-widget-2000", "mapPrice": 99.95, "label": "Pro Widget 2000"}]}'
```

```js
// Node.js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lowlanddata/map-price-violation-monitor').call({
  products: [
    {
      url: 'https://dealer-shop.example.com/products/pro-widget-2000',
      mapPrice: 99.95,
      label: 'Pro Widget 2000',
    },
  ],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
## Python
from apify_client import ApifyClient
client = ApifyClient(token=os.environ["APIFY_TOKEN"])
run = client.actor("lowlanddata/map-price-violation-monitor").call(run_input={
    "products": [{"url": "https://dealer-shop.example.com/products/pro-widget-2000",
                   "mapPrice": 99.95, "label": "Pro Widget 2000"}]})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Keep the product list under ~300 for synchronous calls (the sync endpoint has a
300-second wall); larger lists run fine asynchronously.

### Compliance

This monitor collects **organizational and product data only**: advertised prices,
availability, product names and retailer domains from public product pages — the
same data the shops publish to Google. Personal data (shop-owner names, contact
details, review authors) present in a page's raw structured data is structurally
excluded: output items are built from a fixed whitelist of typed fields, proven by
an automated test that feeds the mapper deliberately person-laden pages. No login
walls are crossed, no anti-bot protections are bypassed, and unreachable shops are
reported as such rather than fought.

MAP enforcement itself is a legal matter that varies by jurisdiction (e.g. US MAP
policies vs EU resale-price rules) — this tool gives you the evidence, not legal
advice.

### Troubleshooting

- **"Invalid input: products: Add at least one product"** — the `products` array
  is empty or malformed; each entry needs at least `url` and `mapPrice`.
- **"Monitor state record 'map-products' is not readable"** — the state store
  holds a record written by an incompatible version. Run once with
  `resetState: true` to start fresh (you'll get a new baseline).
- **`status: "unreadable"` for a shop you can open in a browser** — the shop
  renders its price only in JavaScript or publishes no structured data. Not
  covered in v1; the item is uncharged. The `note` field says what was missing.
- **`status: "unreachable"` with HTTP 403** — the shop blocks datacenter traffic.
  Try a residential proxy (Input → Proxy); if it still blocks, the shop is outside
  honest coverage.
- **`status: "currency-mismatch"`** — the page advertises a different currency
  than the product's `currency` input. Fix the input currency, or set the proxy
  country so the shop serves your target market's prices.
- **Prices look right but alerts reference an old MAP** — you edited `mapPrice`
  and the change alerts only on transitions; an already-known violation at the
  same advertised price and MAP stays silent by design (see "How the monitor
  thinks").

Something else off? Open an issue on the actor's Issues tab — reports are read and
answered.

# Actor input Schema

## `products` (type: `array`):

REQUIRED. Your product list as JSON: one entry per retailer product page, each with url (the product page), mapPrice (your minimum advertised price), optional currency (ISO code, default USD) and optional label. Example: \[{ "url": "https://shop.example.com/products/widget", "mapPrice": 129.95, "label": "Widget Pro" }]. Up to 500 products per run. Tip: the README has a copy-paste AI prompt that converts a pasted price list or spreadsheet into this JSON.

## `alertOn` (type: `string`):

What counts as an alert. 'violations' alerts when a product newly drops below its MAP or an existing violation cuts deeper. 'violations-and-recoveries' additionally alerts when a violating product returns to or above MAP.

## `emitBaseline` (type: `boolean`):

On the first run for a product, push its current price as a baseline item (flagged isBaseline, charged at the low baseline price). Turn off to seed silently: the first run then records state without pushing items.

## `resetState` (type: `boolean`):

Discard everything this monitor remembers and start over: the next run is a fresh baseline for every product. Use after large catalog or MAP policy changes.

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

Upper bound on items pushed per run. Alerts are pushed before baseline snapshots, so a low cap never hides a violation. Transitions that do not fit alert on the next run.

## `stateStoreName` (type: `string`):

Named key-value store holding what the monitor has already seen. Use a different name per independent monitor (e.g. one per brand) so their memories never mix.

## `proxyConfiguration` (type: `object`):

Proxy settings for fetching retailer pages. The default (datacenter) works for the covered long-tail shops.

## Actor input object example

```json
{
  "products": [
    {
      "url": "https://www.clarionsafety.com/products/safety-signs/hazardous-material-signs/chemical-hazard-signs/warning-corrosive-materials-sign-f1243",
      "mapPrice": 5,
      "currency": "USD",
      "label": "Demo — Warning sign F1243 (demo MAP $5)"
    },
    {
      "url": "https://jococups.com/usa/product/12oz-joco-cup/",
      "mapPrice": 19,
      "currency": "USD",
      "label": "Demo — JOCO Cup 12oz (demo MAP $19)"
    },
    {
      "url": "https://monin.com/us/vanilla-syrup",
      "mapPrice": 10,
      "currency": "USD",
      "label": "Demo — Monin Vanilla 750 ml (MAP $10)"
    }
  ],
  "alertOn": "violations",
  "emitBaseline": true,
  "resetState": false,
  "maxItems": 500,
  "stateStoreName": "map-monitor-state",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `alerts` (type: `string`):

One JSON object per monitored product event. On the first run: a baseline price snapshot per product; afterwards: only transitions — new MAP violations, deeper cuts, recoveries and check-status changes.

# 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 = {
    "products": [
        {
            "url": "https://www.clarionsafety.com/products/safety-signs/hazardous-material-signs/chemical-hazard-signs/warning-corrosive-materials-sign-f1243",
            "mapPrice": 5,
            "currency": "USD",
            "label": "Demo — Warning sign F1243 (demo MAP $5)"
        },
        {
            "url": "https://jococups.com/usa/product/12oz-joco-cup/",
            "mapPrice": 19,
            "currency": "USD",
            "label": "Demo — JOCO Cup 12oz (demo MAP $19)"
        },
        {
            "url": "https://monin.com/us/vanilla-syrup",
            "mapPrice": 10,
            "currency": "USD",
            "label": "Demo — Monin Vanilla 750 ml (MAP $10)"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/map-price-violation-monitor").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 = { "products": [
        {
            "url": "https://www.clarionsafety.com/products/safety-signs/hazardous-material-signs/chemical-hazard-signs/warning-corrosive-materials-sign-f1243",
            "mapPrice": 5,
            "currency": "USD",
            "label": "Demo — Warning sign F1243 (demo MAP $5)",
        },
        {
            "url": "https://jococups.com/usa/product/12oz-joco-cup/",
            "mapPrice": 19,
            "currency": "USD",
            "label": "Demo — JOCO Cup 12oz (demo MAP $19)",
        },
        {
            "url": "https://monin.com/us/vanilla-syrup",
            "mapPrice": 10,
            "currency": "USD",
            "label": "Demo — Monin Vanilla 750 ml (MAP $10)",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/map-price-violation-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "products": [
    {
      "url": "https://www.clarionsafety.com/products/safety-signs/hazardous-material-signs/chemical-hazard-signs/warning-corrosive-materials-sign-f1243",
      "mapPrice": 5,
      "currency": "USD",
      "label": "Demo — Warning sign F1243 (demo MAP $5)"
    },
    {
      "url": "https://jococups.com/usa/product/12oz-joco-cup/",
      "mapPrice": 19,
      "currency": "USD",
      "label": "Demo — JOCO Cup 12oz (demo MAP $19)"
    },
    {
      "url": "https://monin.com/us/vanilla-syrup",
      "mapPrice": 10,
      "currency": "USD",
      "label": "Demo — Monin Vanilla 750 ml (MAP $10)"
    }
  ]
}' |
apify call lowlanddata/map-price-violation-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=lowlanddata/map-price-violation-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "MAP Price Violation Monitor & Alerts",
        "description": "Monitor your product list across retailer sites and get alerted the moment a price drops below your MAP (minimum advertised price). Stateful: alerts only on new violations, deeper cuts and recoveries — never repeats. Works on Shopify, WooCommerce, BigCommerce, Magento and custom shops. GDPR-clean.",
        "version": "0.1",
        "x-build-id": "H9101agoucrJipxl7"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/lowlanddata~map-price-violation-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-lowlanddata-map-price-violation-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/lowlanddata~map-price-violation-monitor/runs": {
            "post": {
                "operationId": "runs-sync-lowlanddata-map-price-violation-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/lowlanddata~map-price-violation-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-lowlanddata-map-price-violation-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "products"
                ],
                "properties": {
                    "products": {
                        "title": "Products to monitor",
                        "type": "array",
                        "description": "REQUIRED. Your product list as JSON: one entry per retailer product page, each with url (the product page), mapPrice (your minimum advertised price), optional currency (ISO code, default USD) and optional label. Example: [{ \"url\": \"https://shop.example.com/products/widget\", \"mapPrice\": 129.95, \"label\": \"Widget Pro\" }]. Up to 500 products per run. Tip: the README has a copy-paste AI prompt that converts a pasted price list or spreadsheet into this JSON."
                    },
                    "alertOn": {
                        "title": "Alert on",
                        "enum": [
                            "violations",
                            "violations-and-recoveries"
                        ],
                        "type": "string",
                        "description": "What counts as an alert. 'violations' alerts when a product newly drops below its MAP or an existing violation cuts deeper. 'violations-and-recoveries' additionally alerts when a violating product returns to or above MAP.",
                        "default": "violations"
                    },
                    "emitBaseline": {
                        "title": "Emit baseline snapshot on first run",
                        "type": "boolean",
                        "description": "On the first run for a product, push its current price as a baseline item (flagged isBaseline, charged at the low baseline price). Turn off to seed silently: the first run then records state without pushing items.",
                        "default": true
                    },
                    "resetState": {
                        "title": "Reset monitor state",
                        "type": "boolean",
                        "description": "Discard everything this monitor remembers and start over: the next run is a fresh baseline for every product. Use after large catalog or MAP policy changes.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Max items per run",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Upper bound on items pushed per run. Alerts are pushed before baseline snapshots, so a low cap never hides a violation. Transitions that do not fit alert on the next run.",
                        "default": 500
                    },
                    "stateStoreName": {
                        "title": "State store name",
                        "type": "string",
                        "description": "Named key-value store holding what the monitor has already seen. Use a different name per independent monitor (e.g. one per brand) so their memories never mix.",
                        "default": "map-monitor-state"
                    },
                    "proxyConfiguration": {
                        "title": "Proxy",
                        "type": "object",
                        "description": "Proxy settings for fetching retailer pages. The default (datacenter) works for the covered long-tail shops.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
