# MAP Price Policy Evidence Monitor (`plusonets/map-price-policy-monitor`) Actor

Compare public product-page prices with a brand's own advertised-price rules, reconcile each seller against the supplied approved list, and save one evidence package per material price incident.

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

## Pricing

from $100.00 / 1,000 evidence packages

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

## MAP Price Policy Evidence Monitor

A brand with its own advertised-price rules can point this Actor at product URLs and get a review file: what the page showed, which catalog row and seller it matched, and whether that public price sits below a threshold **the brand supplied**. When a comparable offer is confirmed below that threshold, the Actor writes **one evidence package for that incident** and does not write another package on later runs while the same price is still on the page.

It reports observations. It does not send enforcement messages, and it does not reach a legal conclusion. A seller that is absent from the list you supplied is described as **seller not matched to the supplied list**.

Unofficial, and not affiliated with Shopify, Graza, OLAPLEX, or Beardbrand. The sample reads public product pages those stores already publish. Page text stays on the store; this Actor keeps the extracted fields, a SHA-256 of the bytes it read, and an optional screenshot.

Contact: plusonecares@gmail.com

### Who it is for

Brand operations and agency teams who already have:

- a catalog with SKU, GTIN, or MPN, plus pack size
- advertised-price thresholds and the dates they apply
- an approved-seller list with aliases and domains
- exemptions, when a lower public price is expected
- the exact product URLs to watch

The useful output is a queue a person can review, with the source URL, the time, the fields that were read, and the page hash.

### What you supply

| Input | Required | What it contains |
|---|---|---|
| Product URLs | Yes, unless you run the sample | `url`, and optionally `sku`, `gtin`, `mpn`, `variantId` |
| Catalog | Yes for a real brand | `sku`, `gtin`, `mpn`, `title`, `packSize`, `brand` |
| Policies | Yes for a comparison | `policyId`, `sku`, `minAdvertisedPrice`, `currency`, `effectiveFrom`, optional `effectiveTo`, `packSize`, `appliesToCondition` |
| Approved sellers | Yes for identity | `sellerId`, `name`, `aliases`, `domains` |
| Exemptions | No | `exemptionId`, optional `sku` and `sellerId`, `reason`, dates, `condition`, optional `floorPrice` |

JSON arrays and CSV text are both accepted. CSV columns use the same names. In the seller CSV, separate aliases and domains with `|`.

Leave the URL list and the catalog empty and the Actor runs the built-in sample. That sample is also the prefilled input, so Apify's daily check has a public, stable run.

### What a run does

1. Rejects non-public targets (localhost, private IPs, `file://`, credentials in the URL) before any request.
2. Fetches the product page and, for a Shopify-style URL, the public `products/{handle}.json` document. Requests are throttled, retried with backoff, and sent with an identifying User-Agent.
3. Reads the selected variant, seller, condition (`new`, `used`, `refurbished`), pack quantity, displayed price, currency, and whether **that offer** is a member price, a coupon price, or another conditional price. A promotion mentioned elsewhere on the page is recorded and does not, by itself, exclude the offer.
4. Joins the offer to your catalog by the SKU you supplied or by GTIN, MPN, or SKU on the page. A title-only candidate is reported and is not strong enough to apply a threshold.
5. Joins the seller by domain first (high confidence), then by exact name (medium), then by a fuzzy name (medium or low). Two equally plausible sellers stay `ambiguous`.
6. Compares the price with the policy that is effective on the observation date. Currency must match. Pack and condition must match. There is no currency conversion.
7. When the comparable price is below the supplied minimum, fetches the page again. The evidence package is written only when the second read shows the same price and the same result.
8. Charges `offer-checked` for a completed, validated check, and `evidence-package` the first time that material incident is delivered. The same URL, variant, price, and currency are not charged again on the same UTC day. The same incident is not packaged again while the price is unchanged.

Coverage is one of `complete`, `partial`, `empty`, `blocked`, or `unsupported`. A blocked or empty page is still a dataset row, and it is not charged.

### Sample input

The prefilled run watches three public Shopify product pages:

| Page | Sample rule | What the sample is meant to show |
|---|---|---|
| Graza Hot 'n Sweet Olive Oil Potato Chips (`CHP-HS55`) | minimum USD 24.00 from 2026-01-01 | The public price is below that sample minimum, so a confirmed run writes one evidence package. |
| OLAPLEX The Healthy Hair Travel Set (`VB000030`) | minimum USD 0.01 | A matched seller whose public price is above the supplied minimum. |
| Beardbrand Fox Hunt Men's Cologne (`32836920`) | minimum USD 0.01 | The product is in the catalog. Beardbrand is not on the approved-seller list. |

The USD 24.00 and USD 0.01 figures are sample thresholds, chosen so the demo has one below-threshold offer and two offers above their thresholds. They are not those brands' policies. Prices on the stores can change. If the chip price later moves to USD 24.00 or above, that row becomes `at_or_above_supplied_threshold` and the dataset is still filled.

A test run of this sample in October 2026 returned three `complete` offer checks and one evidence package, with the cologne row carrying the seller note `seller not matched to the supplied list`.

### Output

Dataset rows are flat, so a webhook, a sheet, or a CSV export can filter them. `recordType` is `offer-check` or `evidence-package`.

Offer check from the sample shape. Price values in these examples are illustrative, not the stores' actual prices. On a pay-per-event run, `chargedOfferCheck` is true. Before that pricing is configured, the same row is delivered with `chargedOfferCheck` false and `chargeNote` set to `platform_did_not_charge`.

```json
{
  "recordType": "offer-check",
  "monitorId": "sample",
  "sourceUrl": "https://www.graza.co/products/hot-n-sweet-olive-oil-potato-chips",
  "observedAt": "2026-10-23T15:04:11.000000+00:00",
  "rechecked": true,
  "recheckAgreed": true,
  "coverage": "complete",
  "extractionMethod": "shopify_json",
  "pageHash": "439942313ba358f8a7e5f8803e12bec41bfdb198ff27650e8f2a2462fd03295c",
  "productSku": "CHP-HS55",
  "productGtin": "850062393370",
  "variantId": "48239480438998",
  "variantSelection": "sku",
  "sellerMatchStatus": "matched",
  "sellerMatchConfidence": "high",
  "sellerMatchMethod": "domain",
  "sellerId": "graza",
  "sellerName": "Graza",
  "sellerMatchNote": null,
  "condition": "new",
  "conditionSource": "json_ld",
  "packQuantity": 1,
  "packSource": "assumed_single",
  "price": 20.0,
  "priceCents": 2000,
  "currency": "USD",
  "memberPrice": false,
  "couponPrice": false,
  "conditionalPrice": false,
  "promotionMentioned": true,
  "policyId": "SAMPLE-CHIPS",
  "policyMinAdvertisedPrice": 24.0,
  "policyCurrency": "USD",
  "policyStatus": "below_supplied_threshold",
  "comparable": true,
  "priceDifference": -4.0,
  "evidenceStatus": "created",
  "evidenceId": "ev_4a1b2d079991ee64a9b4bd2e",
  "changedFromPrevious": true,
  "chargedOfferCheck": true
}
```

The evidence package for that incident repeats the extracted fields and adds the confirmation time, the confirmation page hash, `screenshotStatus`, and a factual snippet. `chargedEvidencePackage` is true only on the run that first delivers that package.

A seller that is not on your list looks like this:

```json
{
  "recordType": "offer-check",
  "sourceUrl": "https://www.beardbrand.com/products/fox-hunt-mens-cologne",
  "productSku": "32836920",
  "price": 30.0,
  "currency": "USD",
  "policyStatus": "at_or_above_supplied_threshold",
  "sellerMatchStatus": "not_matched",
  "sellerMatchNote": "seller not matched to the supplied list",
  "evidenceStatus": "not_applicable"
}
```

`policyStatus` values you will actually see:

| Status | Meaning |
|---|---|
| `below_supplied_threshold` | Comparable public price is below the minimum you supplied. Confirmed by a second fetch when recheck is on. |
| `at_or_above_supplied_threshold` | Comparable public price is at or above that minimum. |
| `exempt` | A supplied exemption covers this offer. `exemptionId` says which one. |
| `not_comparable` | Used or refurbished when the rule is for new, a different pack, or a member, coupon, or conditional price. |
| `currency_mismatch` | The page currency and the policy currency differ. No conversion is applied. |
| `recheck_not_confirmed` | The first read was below the threshold and the second read did not agree. No package is written. |
| `product_not_matched` | The page did not join a catalog row by SKU, GTIN, or MPN. |
| `no_policy` | No supplied rule is effective for that SKU on the observation date. |
| `blocked`, via `coverage` | The store did not return a page. That row is not charged. |

The run summary is the `OUTPUT` record in the default key-value store. It includes counts, coverage, charged units, the estimated charge at the Actor's prices, and one line per URL. The named store `map-price-policy-state` (change it with `stateStoreName`) keeps the baseline and the incident ledger under `monitor-{monitorId}`. A run that cannot read that record does not replace it and does not bill a new package.

`alertOnlyOnChange` keeps the summary and writes dataset rows only when the price, policy status, seller match, condition, pack, currency, or coverage changed, plus any new evidence package.

### Pricing

This Actor uses pay-per-event pricing. There is no per-dataset-item event. The platform start event is $0.005 per GB and is covered below.

| Event | When it is charged | Price |
|---|---|---|
| `offer-checked` | A validated offer check was delivered. One charge per URL, variant, price, and currency per UTC day. | $0.01 |
| `evidence-package` | A new material incident was delivered after a confirming recheck. The same price does not create another package on the next run. A changed price is a new incident. | $0.10 |

Failed, blocked, empty, and ambiguous reads are not charged. A recheck that disagrees is not charged. A retry of a result already charged that UTC day is not charged again.

| Workload | Events | Charge |
|---|---|---|
| Sample run: 3 pages, 1 new package | 3 offer checks + 1 package | $0.13 |
| One brand, 200 URLs checked each weekday for a month (about 22 runs) and 30 new incidents | 4,400 offer checks + 30 packages | $47.00 |
| The workload used to illustrate a heavier month: 8,000 checks and 200 new packages | 8,000 + 200 | $100.00 |

A 512 MB run also incurs the platform start event. At $0.005 per GB that is about $0.0025 per run. Screenshot and browser runs use 2048 MB, so the start event is about $0.01 and the run is slower. `maxChargeUsd` stops the run using the prices above. The run also stops when Apify reports that the account's max total charge has been reached. Rows that were not charged are not presented as billed.

When you run it locally without pay-per-event, the Actor still writes the dataset and sets `chargedOfferCheck` and `chargedEvidencePackage` to false, with `chargeNote` of `platform_did_not_charge`.

### Scheduling

Run it daily per brand. Give each brand its own `monitorId`. The next day bills a fresh `offer-checked` event for each validated URL and writes a package only when a new material incident appears, or when a previously open incident's price changes. When an offer is no longer below the threshold, the offer row says `incidentResolution: no_longer_below_supplied_threshold` and the stored incident is closed. That resolution is not an evidence package and is not billed as one.

An errored run does not wipe a good baseline. URLs that fail today keep yesterday's stored observation.

### Integrations

- **Webhook.** Subscribe to the run's succeeded event. Read the default dataset items. Filter `recordType` = `evidence-package` for the review queue, or `policyStatus` = `below_supplied_threshold` for confirmed rows.
- **n8n or Make.** HTTP node to run the Actor, then a dataset node. Map `sourceUrl`, `productSku`, `price`, `currency`, `policyStatus`, `sellerMatchNote`, `evidenceId`, and `pageHash` into the sheet or ticket.
- **Google Sheets.** Export the dataset as CSV. Every field is a column. `notComparableReasons` and `changedFields` are semicolon-separated.
- **Key-value store.** `OUTPUT` is the run summary. Screenshots, when requested, are PNG records named `screenshot-{evidenceId}`.

### Scope and limits

- Static extraction covers Shopify product JSON, JSON-LD offers, and simple HTML price metadata. A browser is used only when you enable a screenshot or a rendered retry, and only after the static fetch.
- Screenshots and rendered retries need a run with at least 1024 MB. The default memory rises to 2048 MB when those switches are on. If memory is lower, the package is still written and `screenshotStatus` is `skipped_low_memory`.
- Condition defaults to `new`, and pack size defaults to 1, when the page does not say otherwise. Both are labeled (`assumed_new_no_signal`, `assumed_single`).
- Out-of-stock pages can still show an advertised price. Availability is recorded. It does not by itself remove the offer from the comparison.
- Shipping, tax, and checkout prices are out of scope. The price is the one displayed on the product page.
- Marketplace pages where several sellers share one URL need a seller name on the page. A domain match is the high-confidence path, which fits the brand's own store and approved retailer domains.
- Overlapping policies that disagree are `policy_ambiguous`. No package is written.
- This version does not convert currency, does not log into stores, and does not draft letters to sellers.

### Run it

```bash
pip install -r requirements.txt
python3 main.py
```

With no `INPUT.json`, or with `{}`, the sample input runs. Memory defaults to 512 MB for static runs and 2048 MB when a screenshot or a browser retry is requested. The memory ceiling is 2048 MB.

```bash
apify push
```

Tests:

```bash
python3 -m pytest tests
MAP_LIVE=1 python3 -m pytest tests/test_live_smoke.py
```

### FAQ

**How is a seller who is not on my list described?**
The row says `seller not matched to the supplied list`. You decide what that means for your program.

**Will every daily run create another evidence package?**
No. A package is tied to the product, seller, URL, condition, pack, currency, policy, and price. The same price on the next run points at the existing package and bills only the offer check, once per UTC day.

**What if the page shows a coupon or a member price?**
If the extracted offer itself is a coupon, member, or other conditional price, the row is `not_comparable` and no package is written. A promotion mentioned somewhere else on the page sets `promotionMentioned` and leaves the public price eligible.

**What if two reads disagree?**
`policyStatus` is `recheck_not_confirmed`. Nothing is billed for that URL on that attempt, and the stored baseline is left as it was.

**Can I bring a spreadsheet?**
Yes. Paste CSV into the CSV fields, or pass the same rows as JSON arrays.

**Is the sample a real policy?**
No. It is a public demo. The chip threshold is set above the price that was on the page when the sample was prepared, so the first successful run can show an evidence package.

# Actor input Schema

## `monitorId` (type: `string`):

Separates saved state when you watch more than one brand from the same Apify account. Letters, numbers, hyphens, and underscores.

## `productUrls` (type: `array`):

Public product-page URLs. Optional sku, gtin, mpn, and variantId tie the page to your catalog. Leave this empty to run the built-in sample.

## `productUrlsCsv` (type: `string`):

Optional CSV with columns url, sku, gtin, mpn, variantId. Used when Product URLs is empty.

## `catalog` (type: `array`):

Your products. Each object needs sku and should include gtin, mpn, title, packSize, and brand.

## `catalogCsv` (type: `string`):

Optional CSV with columns sku, gtin, mpn, title, packSize, brand. Used when Catalog is empty.

## `policies` (type: `array`):

Thresholds you supply. Each rule needs policyId, sku, minAdvertisedPrice, currency, and effectiveFrom (YYYY-MM-DD). Optional effectiveTo, packSize, and appliesToCondition (new, used, or refurbished).

## `policiesCsv` (type: `string`):

Optional CSV with columns policyId, sku, minAdvertisedPrice, currency, effectiveFrom, effectiveTo, packSize, appliesToCondition.

## `approvedSellers` (type: `array`):

Sellers and aliases you supplied. A page that matches none of them is reported as seller not matched to the supplied list.

## `approvedSellersCsv` (type: `string`):

Optional CSV with columns sellerId, name, aliases, domains. Separate aliases and domains with a pipe character.

## `exemptions` (type: `array`):

Offers you want excluded from evidence packages. sku and sellerId are optional filters. floorPrice, when set, is the lowest price the exemption still covers.

## `exemptionsCsv` (type: `string`):

Optional CSV with columns exemptionId, sku, sellerId, reason, effectiveFrom, effectiveTo, condition, floorPrice.

## `useSampleInput` (type: `boolean`):

Turn this off to refuse a run that has no product URLs and no catalog.

## `recheckExceptions` (type: `boolean`):

Fetch the page a second time before writing an evidence package. A disagreement produces no package.

## `alertOnlyOnChange` (type: `boolean`):

Keep the full summary in the OUTPUT record, and write dataset rows for new or changed observations and for new evidence packages.

## `captureScreenshot` (type: `boolean`):

Uses a browser after the static extract. Set the run memory to 2048 MB. The package is still delivered if the screenshot is skipped.

## `allowBrowserEscalation` (type: `boolean`):

Static Shopify JSON and JSON-LD run first. Set the run memory to 2048 MB before enabling this.

## `requestDelayMs` (type: `integer`):

Pause between HTTP requests to the stores you listed.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout.

## `maxUrls` (type: `integer`):

Hard stop for this run. Raise it deliberately; every completed offer check is billable.

## `maxChargeUsd` (type: `number`):

Optional cap using the suggested prices of $0.01 per offer check and $0.10 per evidence package. The run also stops when Apify reports that the platform max total charge is reached. Leave empty for no extra cap.

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

Named key-value store that keeps baselines and delivered incident ids across runs. An unreadable record is not overwritten.

## Actor input object example

```json
{
  "monitorId": "sample",
  "productUrls": [
    {
      "url": "https://www.graza.co/products/hot-n-sweet-olive-oil-potato-chips",
      "sku": "CHP-HS55"
    },
    {
      "url": "https://olaplex.com/products/olaplex-the-healthy-hair-travel-set-us",
      "sku": "VB000030"
    },
    {
      "url": "https://www.beardbrand.com/products/fox-hunt-mens-cologne",
      "sku": "32836920"
    }
  ],
  "productUrlsCsv": "",
  "catalog": [
    {
      "sku": "CHP-HS55",
      "gtin": "850062393370",
      "mpn": "850062393370",
      "title": "Hot 'n Sweet Olive Oil Potato Chips",
      "packSize": 1,
      "brand": "Graza"
    },
    {
      "sku": "VB000030",
      "gtin": null,
      "mpn": "VB000030",
      "title": "THE HEALTHY HAIR TRAVEL SET",
      "packSize": 1,
      "brand": "OLAPLEX"
    },
    {
      "sku": "32836920",
      "gtin": null,
      "mpn": "32836920",
      "title": "Fox Hunt Men's Cologne",
      "packSize": 1,
      "brand": "Beardbrand"
    }
  ],
  "catalogCsv": "",
  "policies": [
    {
      "policyId": "SAMPLE-CHIPS",
      "sku": "CHP-HS55",
      "minAdvertisedPrice": 24,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    },
    {
      "policyId": "SAMPLE-OLAPLEX",
      "sku": "VB000030",
      "minAdvertisedPrice": 0.01,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    },
    {
      "policyId": "SAMPLE-COLOGNE",
      "sku": "32836920",
      "minAdvertisedPrice": 0.01,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    }
  ],
  "policiesCsv": "",
  "approvedSellers": [
    {
      "sellerId": "graza",
      "name": "Graza",
      "aliases": [
        "Graza",
        "Graza Olive Oil"
      ],
      "domains": [
        "graza.co",
        "www.graza.co"
      ]
    },
    {
      "sellerId": "olaplex",
      "name": "OLAPLEX",
      "aliases": [
        "OLAPLEX",
        "OLAPLEX Inc.",
        "Olaplex"
      ],
      "domains": [
        "olaplex.com",
        "www.olaplex.com"
      ]
    }
  ],
  "approvedSellersCsv": "",
  "exemptions": [
    {
      "exemptionId": "SAMPLE-UNUSED",
      "sku": "NOT-IN-THIS-RUN",
      "sellerId": "graza",
      "reason": "Example exemption shape. It does not match the sample URLs.",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": "2026-12-31",
      "condition": "new",
      "floorPrice": null
    }
  ],
  "exemptionsCsv": "",
  "useSampleInput": true,
  "recheckExceptions": true,
  "alertOnlyOnChange": false,
  "captureScreenshot": false,
  "allowBrowserEscalation": false,
  "requestDelayMs": 800,
  "requestTimeoutSecs": 20,
  "maxUrls": 100,
  "stateStoreName": "map-price-policy-state"
}
```

# Actor output Schema

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

Flat dataset items. Use recordType offer-check or evidence-package.

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

Coverage, counts, charged units, and per-URL status.

# 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 = {
    "monitorId": "sample",
    "productUrls": [
        {
            "url": "https://www.graza.co/products/hot-n-sweet-olive-oil-potato-chips",
            "sku": "CHP-HS55"
        },
        {
            "url": "https://olaplex.com/products/olaplex-the-healthy-hair-travel-set-us",
            "sku": "VB000030"
        },
        {
            "url": "https://www.beardbrand.com/products/fox-hunt-mens-cologne",
            "sku": "32836920"
        }
    ],
    "catalog": [
        {
            "sku": "CHP-HS55",
            "gtin": "850062393370",
            "mpn": "850062393370",
            "title": "Hot 'n Sweet Olive Oil Potato Chips",
            "packSize": 1,
            "brand": "Graza"
        },
        {
            "sku": "VB000030",
            "gtin": null,
            "mpn": "VB000030",
            "title": "THE HEALTHY HAIR TRAVEL SET",
            "packSize": 1,
            "brand": "OLAPLEX"
        },
        {
            "sku": "32836920",
            "gtin": null,
            "mpn": "32836920",
            "title": "Fox Hunt Men's Cologne",
            "packSize": 1,
            "brand": "Beardbrand"
        }
    ],
    "policies": [
        {
            "policyId": "SAMPLE-CHIPS",
            "sku": "CHP-HS55",
            "minAdvertisedPrice": 24,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": null,
            "packSize": 1,
            "appliesToCondition": "new"
        },
        {
            "policyId": "SAMPLE-OLAPLEX",
            "sku": "VB000030",
            "minAdvertisedPrice": 0.01,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": null,
            "packSize": 1,
            "appliesToCondition": "new"
        },
        {
            "policyId": "SAMPLE-COLOGNE",
            "sku": "32836920",
            "minAdvertisedPrice": 0.01,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": null,
            "packSize": 1,
            "appliesToCondition": "new"
        }
    ],
    "approvedSellers": [
        {
            "sellerId": "graza",
            "name": "Graza",
            "aliases": [
                "Graza",
                "Graza Olive Oil"
            ],
            "domains": [
                "graza.co",
                "www.graza.co"
            ]
        },
        {
            "sellerId": "olaplex",
            "name": "OLAPLEX",
            "aliases": [
                "OLAPLEX",
                "OLAPLEX Inc.",
                "Olaplex"
            ],
            "domains": [
                "olaplex.com",
                "www.olaplex.com"
            ]
        }
    ],
    "exemptions": [
        {
            "exemptionId": "SAMPLE-UNUSED",
            "sku": "NOT-IN-THIS-RUN",
            "sellerId": "graza",
            "reason": "Example exemption shape. It does not match the sample URLs.",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": "2026-12-31",
            "condition": "new",
            "floorPrice": null
        }
    ],
    "stateStoreName": "map-price-policy-state"
};

// Run the Actor and wait for it to finish
const run = await client.actor("plusonets/map-price-policy-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 = {
    "monitorId": "sample",
    "productUrls": [
        {
            "url": "https://www.graza.co/products/hot-n-sweet-olive-oil-potato-chips",
            "sku": "CHP-HS55",
        },
        {
            "url": "https://olaplex.com/products/olaplex-the-healthy-hair-travel-set-us",
            "sku": "VB000030",
        },
        {
            "url": "https://www.beardbrand.com/products/fox-hunt-mens-cologne",
            "sku": "32836920",
        },
    ],
    "catalog": [
        {
            "sku": "CHP-HS55",
            "gtin": "850062393370",
            "mpn": "850062393370",
            "title": "Hot 'n Sweet Olive Oil Potato Chips",
            "packSize": 1,
            "brand": "Graza",
        },
        {
            "sku": "VB000030",
            "gtin": None,
            "mpn": "VB000030",
            "title": "THE HEALTHY HAIR TRAVEL SET",
            "packSize": 1,
            "brand": "OLAPLEX",
        },
        {
            "sku": "32836920",
            "gtin": None,
            "mpn": "32836920",
            "title": "Fox Hunt Men's Cologne",
            "packSize": 1,
            "brand": "Beardbrand",
        },
    ],
    "policies": [
        {
            "policyId": "SAMPLE-CHIPS",
            "sku": "CHP-HS55",
            "minAdvertisedPrice": 24,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": None,
            "packSize": 1,
            "appliesToCondition": "new",
        },
        {
            "policyId": "SAMPLE-OLAPLEX",
            "sku": "VB000030",
            "minAdvertisedPrice": 0.01,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": None,
            "packSize": 1,
            "appliesToCondition": "new",
        },
        {
            "policyId": "SAMPLE-COLOGNE",
            "sku": "32836920",
            "minAdvertisedPrice": 0.01,
            "currency": "USD",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": None,
            "packSize": 1,
            "appliesToCondition": "new",
        },
    ],
    "approvedSellers": [
        {
            "sellerId": "graza",
            "name": "Graza",
            "aliases": [
                "Graza",
                "Graza Olive Oil",
            ],
            "domains": [
                "graza.co",
                "www.graza.co",
            ],
        },
        {
            "sellerId": "olaplex",
            "name": "OLAPLEX",
            "aliases": [
                "OLAPLEX",
                "OLAPLEX Inc.",
                "Olaplex",
            ],
            "domains": [
                "olaplex.com",
                "www.olaplex.com",
            ],
        },
    ],
    "exemptions": [{
            "exemptionId": "SAMPLE-UNUSED",
            "sku": "NOT-IN-THIS-RUN",
            "sellerId": "graza",
            "reason": "Example exemption shape. It does not match the sample URLs.",
            "effectiveFrom": "2026-01-01",
            "effectiveTo": "2026-12-31",
            "condition": "new",
            "floorPrice": None,
        }],
    "stateStoreName": "map-price-policy-state",
}

# Run the Actor and wait for it to finish
run = client.actor("plusonets/map-price-policy-monitor").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 '{
  "monitorId": "sample",
  "productUrls": [
    {
      "url": "https://www.graza.co/products/hot-n-sweet-olive-oil-potato-chips",
      "sku": "CHP-HS55"
    },
    {
      "url": "https://olaplex.com/products/olaplex-the-healthy-hair-travel-set-us",
      "sku": "VB000030"
    },
    {
      "url": "https://www.beardbrand.com/products/fox-hunt-mens-cologne",
      "sku": "32836920"
    }
  ],
  "catalog": [
    {
      "sku": "CHP-HS55",
      "gtin": "850062393370",
      "mpn": "850062393370",
      "title": "Hot '\''n Sweet Olive Oil Potato Chips",
      "packSize": 1,
      "brand": "Graza"
    },
    {
      "sku": "VB000030",
      "gtin": null,
      "mpn": "VB000030",
      "title": "THE HEALTHY HAIR TRAVEL SET",
      "packSize": 1,
      "brand": "OLAPLEX"
    },
    {
      "sku": "32836920",
      "gtin": null,
      "mpn": "32836920",
      "title": "Fox Hunt Men'\''s Cologne",
      "packSize": 1,
      "brand": "Beardbrand"
    }
  ],
  "policies": [
    {
      "policyId": "SAMPLE-CHIPS",
      "sku": "CHP-HS55",
      "minAdvertisedPrice": 24,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    },
    {
      "policyId": "SAMPLE-OLAPLEX",
      "sku": "VB000030",
      "minAdvertisedPrice": 0.01,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    },
    {
      "policyId": "SAMPLE-COLOGNE",
      "sku": "32836920",
      "minAdvertisedPrice": 0.01,
      "currency": "USD",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": null,
      "packSize": 1,
      "appliesToCondition": "new"
    }
  ],
  "approvedSellers": [
    {
      "sellerId": "graza",
      "name": "Graza",
      "aliases": [
        "Graza",
        "Graza Olive Oil"
      ],
      "domains": [
        "graza.co",
        "www.graza.co"
      ]
    },
    {
      "sellerId": "olaplex",
      "name": "OLAPLEX",
      "aliases": [
        "OLAPLEX",
        "OLAPLEX Inc.",
        "Olaplex"
      ],
      "domains": [
        "olaplex.com",
        "www.olaplex.com"
      ]
    }
  ],
  "exemptions": [
    {
      "exemptionId": "SAMPLE-UNUSED",
      "sku": "NOT-IN-THIS-RUN",
      "sellerId": "graza",
      "reason": "Example exemption shape. It does not match the sample URLs.",
      "effectiveFrom": "2026-01-01",
      "effectiveTo": "2026-12-31",
      "condition": "new",
      "floorPrice": null
    }
  ],
  "stateStoreName": "map-price-policy-state"
}' |
apify call plusonets/map-price-policy-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,plusonets/map-price-policy-monitor"
        }
    }
}
```

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/hEXtu23WX5ntW3LBJ/builds/C2s0JXgvVkhMO4bPn/openapi.json
