# Amazon Review Defect Finder (`pradio/amazon-defect-ledger`) Actor

Paste an Amazon product URL and see which complaints are real patterns. It fetches the critical reviews and returns each recurring fault, how many separate reviewers named it, how many times it was mentioned, the first and last date seen, the worst star rating, and their exact words.

- **URL**: https://apify.com/pradio/amazon-defect-ledger.md
- **Developed by:** [E A](https://apify.com/pradio) (community)
- **Categories:** E-commerce, AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $15.00 / 1,000 defect cluster founds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Amazon Review Defect Finder

Find out which product complaints are REAL patterns and which are one-off grumbles.

**Paste an Amazon product URL and it does the rest.** It fetches the critical reviews,
groups the complaints more than one person made, and hands you a ledger: each named fault
with how many separate reviewers reported it, the date range, the worst star rating, and
their own words as evidence.

**Who it is for.** Sellers and brand owners watching their own listings, and equally buyers,
sourcing teams and researchers looking at a product they do NOT own. You need no seller
account and no ownership — a competitor's product works exactly as well as your own.

Most review tools give you raw data. This one tells you which complaint is a **pattern** and
which is one person having a bad week.

### Run it in ten seconds

Paste a product URL into **Amazon product URL(s)** and press Start:

```json
{
  "productUrls": ["https://www.amazon.com/dp/B0BSHF7WHW"],
  "maxReviews": 100,
  "minCorroboration": 3
}
```

It fetches **only the 1-3★ reviews** — the ones that can carry a defect — so you are not
billed for five-star reviews it would only discard. Out comes one row per corroborated fault.

**Leave the URL blank and press Start anyway.** The Actor ships with a worked example in the
`reviews` field, so you get a real ledger for free before spending anything:

```json
{
  "reviews": [
    { "userId": "R1", "date": "2026-03-02", "ratingScore": 2,
      "reviewDescription": "The left earbud stopped charging after about four months. Case shows it at 100% but it is dead." },
    { "userId": "R2", "date": "2026-03-19", "ratingScore": 1,
      "reviewDescription": "Left bud stopped charging completely around month five. Right one is fine." },
    { "userId": "R3", "date": "2026-04-07", "ratingScore": 2,
      "reviewDescription": "Battery died on the left earbud after four months of light use." }
  ],
  "minCorroboration": 3,
  "productName": "Wireless Earbuds (example)"
}
```

and the ledger row it produces:

```json
{
  "result": "DEFECT_CLUSTER",
  "asin": "_all",
  "product": "Wireless Earbuds (example)",
  "defectPhrase": "left earbud",
  "distinctReviewers": 3,
  "totalMentions": 3,
  "firstSeen": "2026-03-02",
  "lastSeen": "2026-04-07",
  "severityMinRating": 1,
  "exampleQuotes": [
    {
      "text": "The left earbud stopped charging after about four months",
      "userId": "R1",
      "date": "2026-03-02"
    },
    {
      "text": "Left bud stopped charging completely around month five",
      "userId": "R2",
      "date": "2026-03-19"
    },
    {
      "text": "Battery died on the left earbud after four months of light use",
      "userId": "R3",
      "date": "2026-04-07"
    }
  ]
}
```

That is the **actual output** of the input above, captured from a real run — not a mock-up.
The review text is illustrative; the row is what the Actor produced.

`distinctReviewers: 3` is the number that matters. Three separate people, three separate
dates, describing the same physical failure — that is a defect. One person saying it twice is
not, and this counts users rather than mentions so the two never look alike.

When nothing clears the threshold you get a row saying so, rather than an empty dataset that
could mean anything:

```json
{ "result": "NO_CORROBORATED_DEFECTS", "why": "no failure was named by 3 or more distinct reviewers" }
```

### Output fields

| Field | Meaning |
|---|---|
| `result` | `DEFECT_CLUSTER`, or a status row when there is nothing to report |
| `asin` | the product group this cluster belongs to, or `_all` when reviews carry no ASIN |
| `product` | the `productName` you passed |
| `defectPhrase` | the dominant phrase across the cluster, in reviewers' own words |
| `distinctReviewers` | how many DIFFERENT people named it — the corroboration count |
| `totalMentions` | how many times it was named, which can exceed the reviewer count |
| `firstSeen` / `lastSeen` | the date range, so you can see whether it is old or current |
| `criticalReviewsAnalysed` | how many 1-3★ reviews were read. On EVERY row — the denominator |
| `failureSentencesFound` | how many sentences carried failure language |
| `clustersFound` | how many distinct faults were grouped, before the corroboration cut |
| `clustersBelowThreshold` | how many of those had too few distinct reviewers to report |
| `why` | on a status row, the sentence explaining why there is nothing to report |
| `minCorroboration` | the threshold this run used |
| `analysedAt` | when the ledger was built — a saved ledger cannot say it is still true |
| `severityMinRating` | the lowest star rating among the reviews in this cluster |
| `exampleQuotes` | verbatim evidence, with the user and date behind each one |
| `productUrl` | the link back to the product: `linkUrl` if you set it, otherwise the first URL you fetched with. `null` if you gave neither |

`firstSeen` and `lastSeen` are worth reading together. A cluster spanning eight months is a
manufacturing problem; one spanning eight days is often a single bad batch.

### What you get

Each dataset item is a **defect cluster** — one named product failure corroborated by
multiple independent reviewers, with dates, severity and verbatim evidence. When no
defect meets the corroboration threshold, you get an explicit record saying so — never
silence, never an empty dataset that could mean anything.

### How to use it

**Paste a product URL.** That is the whole thing. It fetches the critical reviews and builds
the ledger in one run.

Amazon gives sellers no export of review text — Voice of the Customer exports returns and
customer-experience data, and "download feedback reports" is *seller* feedback. So the
reviews have to be scraped, and this does it for you rather than sending you off to do it.

If you already have review data, two other ways in:

- **A dataset you already produced.** Put its ID in `reviewsDatasetId`. Set it to
  `{{resource.defaultDatasetId}}` on a scraper's **Integrations** tab and that scraper feeds
  this Actor automatically, on whatever schedule you give it.
- **Paste the objects** into `reviews`. Fine for a handful or a hand-assembled set.

A product URL takes priority over both. Clear it to use the review data instead.

### What makes this different

Every bulk review tool gives quantity. None tell you whether a complaint is a real
recurring defect or noise. This one counts DISTINCT reviewers per named failure —
so you know "battery dies after 6 months" reported by 12 independent people is
different from "hated the colour" mentioned once.

### Input

| Field | Default | Description |
|---|---|---|
| `productUrls` | *(empty)* | **Start here.** One or more Amazon product URLs. It fetches the 1-3★ reviews itself and builds the ledger. Takes priority over the two fields below. |
| `maxReviews` | `100` | Caps how many **critical** reviews are fetched — five-star reviews are never requested, so this is the number you are billed for. Only applies when you give a product URL. |
| `reviewsScraperActor` | `junglee/amazon-reviews-scraper` | Which Store Actor does the fetching. Change it if you prefer another; it must return objects carrying review text, a rating, a reviewer id and a date. |
| `reviews` | *(prefilled)* | Review objects (JSON), if you already have them. Arrives filled with a worked example, so Start works before you change anything. |
| `reviewsDatasetId` | *(optional)* | The dataset ID of a run that produced reviews. Set it to `{{resource.defaultDatasetId}}` in an Integration and a scraper feeds this Actor automatically. |
| `minCorroboration` | `3` | Minimum distinct reviewers per defect to appear in the ledger |
| `productName` | *(optional)* | Human-readable label for the ledger entries |
| `linkUrl` | *(optional)* | A link copied onto every row so you can click back to the product. Only needed when you supply reviews yourself; if you gave a product URL, that one is used. Never fetched. |

Give it **a product URL**, *or* `reviews`, *or* `reviewsDatasetId`. A URL wins over the other
two, because a URL is something you typed and the prefilled reviews are a sample you did not
choose. The log says so when it ignores something.

Two failures are reported as their own rows rather than as an empty result, because a run
that could not look and a product with no defects are different answers:

- `REVIEW_FETCH_FAILED` — a URL was given and the fetch returned nothing usable.
- `REVIEWS_DATASET_UNREADABLE` — a dataset ID was given and could not be opened.

### Honest limits

**On a free Apify plan the fetch returns at most 10 reviews, from one product URL.** That is
the review scraper's own limit, not ours, and you will meet it before you meet anything else:
ten critical reviews rarely contain three people naming the same fault, so a free-plan run
will often return `NO_CORROBORATED_DEFECTS` on a product that genuinely has a defect.
Measured on a real product 2026-08-27: 10 reviews fetched, 5 failure mentions, 5 candidate
faults, none reaching even two distinct reviewers. Raise `maxReviews` on a paid plan, or
supply reviews you already have.

**It under-reports, and you should know how.** Two reviewers are joined into one defect
only when they use the same two-word phrase. Measured: *"Case hinge snapped in my pocket"*
and *"the hinge on the charging case broke"* share no two-word phrase, so they do not
cluster — even though both name the hinge. Short sentences are also dropped: *"Hinge
cracked."* is below the length floor and never reaches the clustering step at all.

So a `NO_CORROBORATED_DEFECTS` result means **no defect was named the same way by enough
people**, which is not the same as no defect existing. Read the reviews yourself before
concluding a product is clean.
This is deliberate: a defect it missed costs you a second look at the reviews, while one it
invented would cost you a decision you cannot take back.

- It does not judge quality, only corroboration. Three people reporting the same fault is a
  pattern; whether that fault matters is your call, not a number this returns.
- The fetch is done by a separate review-scraper Actor, so its coverage and its limits become
  this Actor's. If it returns nothing for a product, you get `REVIEW_FETCH_FAILED` rather than
  a clean bill of health.
- Clustering uses bigram overlap on failure-language sentences. It finds recurring
  themes; it does not perform NLP-level semantic understanding of each complaint.

### Questions

**What review shape does it accept?** Objects with the text under `text` or
`reviewDescription`, the score under `rating` or `ratingScore`, plus `userId` and `date`.
Output from the common Store scrapers works without reshaping.

**Should I filter to 1-3 star reviews first?** You do not have to, because this Actor does
it for you — and you should know that it does. Every review rated 4 or 5 is dropped before
any text is read, so a fault mentioned inside a five-star review does **not** contribute to
a cluster and is not counted in `criticalReviewsAnalysed`. Send everything and the filter
runs here; filter first and you only save scraping cost.

**Why did it find fewer defects than I expected?** See the limits section above; it under-
reports on purpose and the reason is mechanical rather than mysterious.

**Does it work for multiple products at once?** Yes. Reviews are grouped by ASIN before
clustering, so a mixed dataset gives you one ledger per product rather than one blend.

### Pricing

Pay per event. There are exactly two, and these are the prices the platform charges:

| Event | Price | When |
|---|---|---|
| `defect-cluster-found` | **$0.015** | once per corroborated defect cluster in the ledger |
| `apify-actor-start` | **$0.00005** | once per gigabyte of memory, when the run starts |

So a run that finds 5 corroborated defects costs about **$0.075** — 5 x $0.015, plus a
single start event at $0.00005.

This Actor runs in **256 MB**, which is under a gigabyte, so the start event is charged
exactly once per run whatever the review count.

**When you give a product URL, you pay two publishers.** The fetch runs a separate review
scraper on your account and its publisher bills you for that run — the default charges about
$0.006 per review returned, so 100 critical reviews is roughly **$0.60**, on top of what this
Actor charges. `maxReviews` caps it. Supplying your own reviews or a dataset ID costs nothing
extra, because nothing is fetched.

**Filtering happens before you are charged for anything.** Dropping the 4-5 star reviews,
reading the critical ones and grouping them are all free; the only per-unit charge is a
corroborated cluster in your results. So what a run costs follows the number of **defects
found**, not the number of reviews you send: ten thousand reviews producing three clusters
cost the same as fifty reviews producing three.

**A run that finds nothing charges no `defect-cluster-found` events at all.** Complaints
that no one else corroborated are NOT reported at all — they are counted in
`clustersBelowThreshold` and nothing else, because you are paying for the
finding rather than for the reading.

That covers every outcome where there is nothing to report, including a run that stops
because a dataset ID could not be read. The start event is charged by Apify on every run
whatever happens, so a run that finds nothing costs $0.00005 and never more.

`apify-actor-start` is Apify's own platform event, charged on every pay-per-event Actor
rather than added by this one. No per-row event is billed alongside the cluster event, so
one unit of work is billed once.

### Where the reviews come from

Give it a product URL and it fetches them, using
[junglee/amazon-reviews-scraper](https://apify.com/junglee/amazon-reviews-scraper) by default —
the most used Amazon review scraper on the Store. You can point `reviewsScraperActor` at a
different one if you prefer.

Only the 1-3★ reviews are fetched. A five-star review cannot carry a defect, and fetching one
would cost you money for data this discards.

You can also bring your own, from any scraper, a Seller Central export, a helpdesk, or a CSV
a colleague sent you: if it has a reviewer id, a date, a rating and the text, this reads it.

The companion to this one is
[Apify Store Intelligence](https://apify.com/pradio/store-intel), which applies the same
corroboration-before-conclusion idea to a marketplace rather than a product.

### Integrations

An ordinary Apify Actor, so the whole platform works with it: schedule it, call it from the
[Apify API](https://docs.apify.com/api/v2) or the JavaScript and Python clients, wire it
into Zapier, Make, n8n, Slack or a webhook, or reach it from an AI agent over MCP. Output
is a dataset you can export as JSON, CSV or Excel.

The obvious chain is a review scraper on a schedule feeding this one, so a defect that is newly
corroborated reaches you the week it crosses the threshold rather than the quarter. Set it up on
the scraper's **Integrations** tab with `reviewsDatasetId` = `{{resource.defaultDatasetId}}`.

### Why it never invents a link

Every row can carry a link back to the product, because a defect cluster you cannot trace to
a listing is an interesting fact you can do nothing with.

It would be easy to build that link from the ASIN — `amazon.com/dp/<asin>` — and it would be
**wrong for every review set that is not from the US store**. This Actor never fetches the
product page, so it does not know whether your reviews came from .com, .co.uk, .de or .co.jp,
and a link that is right most of the time is worse than no link at all: nobody checks the
ones that look plausible.

So you supply it, or you leave it blank and the field is `null`. Guessed and absent are
different answers, and this returns the honest one.

### Found a problem?

Report it on the [Issues tab](https://apify.com/pradio/amazon-defect-ledger/issues). Paste
the reviews that produced the wrong answer if you can share them; a description of the fault
the ledger missed is enough if you cannot.

The most useful report is a real defect this failed to cluster. That is the direction it
errs in, and a concrete example is what gets the threshold changed.

### Unofficial

Not affiliated with or endorsed by Amazon or Apify. It reads review data you supply and
contacts no third-party service.

# Actor input Schema

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

Paste one or more Amazon product URLs and this fetches the critical reviews itself, then builds the ledger. Only 1-3 star reviews are fetched, so you are not billed for reviews that cannot produce a finding. The fetch runs a separate review-scraper Actor on YOUR account and its publisher bills you for that run, on top of this one. Leave blank if you already have review data and are using the fields below instead. Left empty, this Actor runs on the worked example below so you can see a real ledger for free before spending anything.

## `maxReviews` (type: `integer`):

Caps how many CRITICAL reviews are fetched. Five-star reviews are never requested, so this is the number the review scraper bills you for. On a free Apify plan the scraper returns at most 10 whatever you set here. Only applies when you give a product URL.

## `reviewsScraperActor` (type: `string`):

Which Store Actor fetches the reviews. The default is the most used Amazon review scraper on the Store. Change it if you prefer another; it must return objects carrying the review text, a rating, a reviewer id and a date.

## `reviews` (type: `array`):

Array of review objects, each with the text under text or reviewDescription, the score under rating or ratingScore, plus userId and date. Supply these OR reviewsDatasetId. Accepts output from any Amazon review scraper or a manual export. Arrives filled with a worked example, so pressing Start produces a real ledger before you change anything.

## `reviewsDatasetId` (type: `string`):

Instead of pasting reviews, give the dataset ID of a run that produced them — for example an Amazon Reviews Scraper run. Items are read from that dataset and used as the reviews. This is what makes the Actor chainable: in an Integration, set this to {{resource.defaultDatasetId}} and a scraper run will feed this one automatically. Leave blank if you are supplying reviews directly.

## `minCorroboration` (type: `integer`):

A defect must be named by at least this many DISTINCT reviewers to appear in the ledger

## `productName` (type: `string`):

Human-readable product label for the ledger entries

## `linkUrl` (type: `string`):

Copied onto every row so you can click back to the product. Only needed when you supply reviews yourself — if you gave a product URL above, that one is used automatically. Never fetched: this Actor does not guess which Amazon marketplace your reviews came from, so a link it invented would be wrong for every .co.uk, .de and .co.jp set.

## Actor input object example

```json
{
  "maxReviews": 100,
  "reviewsScraperActor": "junglee/amazon-reviews-scraper",
  "reviews": [
    {
      "userId": "R1",
      "date": "2026-03-02",
      "ratingScore": 2,
      "reviewDescription": "The left earbud stopped charging after about four months. Case shows it at 100% but it is dead."
    },
    {
      "userId": "R2",
      "date": "2026-03-19",
      "ratingScore": 1,
      "reviewDescription": "Left bud stopped charging completely around month five. Right one is fine."
    },
    {
      "userId": "R3",
      "date": "2026-04-07",
      "ratingScore": 2,
      "reviewDescription": "Battery died on the left earbud after four months of light use. Very disappointing."
    },
    {
      "userId": "R4",
      "date": "2026-02-11",
      "ratingScore": 1,
      "reviewDescription": "Case hinge snapped in my pocket within a few weeks. The plastic is far too thin."
    },
    {
      "userId": "R5",
      "date": "2026-05-02",
      "ratingScore": 2,
      "reviewDescription": "The hinge on the charging case broke after about three weeks of normal use."
    },
    {
      "userId": "R6",
      "date": "2026-05-14",
      "ratingScore": 1,
      "reviewDescription": "Hinge cracked and now the case will not stay shut at all."
    },
    {
      "userId": "R7",
      "date": "2026-01-30",
      "ratingScore": 3,
      "reviewDescription": "Did not like the colour, it is more grey than silver in person."
    }
  ],
  "minCorroboration": 3,
  "productName": "Wireless Earbuds (example)",
  "linkUrl": "https://www.amazon.com/dp/B08EXAMPLE"
}
```

# Actor output Schema

## `ledger` (type: `string`):

All defect clusters for the analysed ASINs.

# 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 = {
    "reviews": [
        {
            "userId": "R1",
            "date": "2026-03-02",
            "ratingScore": 2,
            "reviewDescription": "The left earbud stopped charging after about four months. Case shows it at 100% but it is dead."
        },
        {
            "userId": "R2",
            "date": "2026-03-19",
            "ratingScore": 1,
            "reviewDescription": "Left bud stopped charging completely around month five. Right one is fine."
        },
        {
            "userId": "R3",
            "date": "2026-04-07",
            "ratingScore": 2,
            "reviewDescription": "Battery died on the left earbud after four months of light use. Very disappointing."
        },
        {
            "userId": "R4",
            "date": "2026-02-11",
            "ratingScore": 1,
            "reviewDescription": "Case hinge snapped in my pocket within a few weeks. The plastic is far too thin."
        },
        {
            "userId": "R5",
            "date": "2026-05-02",
            "ratingScore": 2,
            "reviewDescription": "The hinge on the charging case broke after about three weeks of normal use."
        },
        {
            "userId": "R6",
            "date": "2026-05-14",
            "ratingScore": 1,
            "reviewDescription": "Hinge cracked and now the case will not stay shut at all."
        },
        {
            "userId": "R7",
            "date": "2026-01-30",
            "ratingScore": 3,
            "reviewDescription": "Did not like the colour, it is more grey than silver in person."
        }
    ],
    "productName": "Wireless Earbuds (example)",
    "linkUrl": "https://www.amazon.com/dp/B08EXAMPLE"
};

// Run the Actor and wait for it to finish
const run = await client.actor("pradio/amazon-defect-ledger").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 = {
    "reviews": [
        {
            "userId": "R1",
            "date": "2026-03-02",
            "ratingScore": 2,
            "reviewDescription": "The left earbud stopped charging after about four months. Case shows it at 100% but it is dead.",
        },
        {
            "userId": "R2",
            "date": "2026-03-19",
            "ratingScore": 1,
            "reviewDescription": "Left bud stopped charging completely around month five. Right one is fine.",
        },
        {
            "userId": "R3",
            "date": "2026-04-07",
            "ratingScore": 2,
            "reviewDescription": "Battery died on the left earbud after four months of light use. Very disappointing.",
        },
        {
            "userId": "R4",
            "date": "2026-02-11",
            "ratingScore": 1,
            "reviewDescription": "Case hinge snapped in my pocket within a few weeks. The plastic is far too thin.",
        },
        {
            "userId": "R5",
            "date": "2026-05-02",
            "ratingScore": 2,
            "reviewDescription": "The hinge on the charging case broke after about three weeks of normal use.",
        },
        {
            "userId": "R6",
            "date": "2026-05-14",
            "ratingScore": 1,
            "reviewDescription": "Hinge cracked and now the case will not stay shut at all.",
        },
        {
            "userId": "R7",
            "date": "2026-01-30",
            "ratingScore": 3,
            "reviewDescription": "Did not like the colour, it is more grey than silver in person.",
        },
    ],
    "productName": "Wireless Earbuds (example)",
    "linkUrl": "https://www.amazon.com/dp/B08EXAMPLE",
}

# Run the Actor and wait for it to finish
run = client.actor("pradio/amazon-defect-ledger").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 '{
  "reviews": [
    {
      "userId": "R1",
      "date": "2026-03-02",
      "ratingScore": 2,
      "reviewDescription": "The left earbud stopped charging after about four months. Case shows it at 100% but it is dead."
    },
    {
      "userId": "R2",
      "date": "2026-03-19",
      "ratingScore": 1,
      "reviewDescription": "Left bud stopped charging completely around month five. Right one is fine."
    },
    {
      "userId": "R3",
      "date": "2026-04-07",
      "ratingScore": 2,
      "reviewDescription": "Battery died on the left earbud after four months of light use. Very disappointing."
    },
    {
      "userId": "R4",
      "date": "2026-02-11",
      "ratingScore": 1,
      "reviewDescription": "Case hinge snapped in my pocket within a few weeks. The plastic is far too thin."
    },
    {
      "userId": "R5",
      "date": "2026-05-02",
      "ratingScore": 2,
      "reviewDescription": "The hinge on the charging case broke after about three weeks of normal use."
    },
    {
      "userId": "R6",
      "date": "2026-05-14",
      "ratingScore": 1,
      "reviewDescription": "Hinge cracked and now the case will not stay shut at all."
    },
    {
      "userId": "R7",
      "date": "2026-01-30",
      "ratingScore": 3,
      "reviewDescription": "Did not like the colour, it is more grey than silver in person."
    }
  ],
  "productName": "Wireless Earbuds (example)",
  "linkUrl": "https://www.amazon.com/dp/B08EXAMPLE"
}' |
apify call pradio/amazon-defect-ledger --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pradio/amazon-defect-ledger"
        }
    }
}

```

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/LLZbfkjX3z4dweWeT/builds/BxTQ1gNfdOB7a5O6K/openapi.json
