Watchlists

Up to 50,000 items of one platform and marketplace (ASINs, Walmart item ids, TCINs, SKUs…) re-checked on a cadence by a pipeline of scrapers and rules you choose (default on Amazon: the pulse → lite → full ladder; on one-tier retailers: a fetch and diff of every item); changes and matches pushed to a signed webhook. Billed as the calls each run makes.

Embed
Preview of the card
<a href="https://scrapelyserp.com/reference/watchlists"><img src="https://scrapelyserp.com/reference/_api/public/orgs/affc5b0f-d3c2-423a-8143-9d10db5736ae/spaces/e4cbe065-c1c2-4572-b134-0292dedd9c39/pages/0af8a51e-28b7-4b48-b49f-60c78296045c/social-card.svg?v=3e7ae33eec8b" alt="Watchlists" width="600" height="315"></a>

Up to 50,000 items of one platform and marketplace (ASINs, Walmart item ids, TCINs, SKUs…) re-checked on a cadence by a pipeline of scrapers and rules you choose (default on Amazon: the pulse → lite → full ladder; on one-tier retailers: a fetch and diff of every item); changes and matches pushed to a signed webhook. Billed as the calls each run makes.

Endpoints

Method

Path

Does

POST

/v1/watchlists

Create a watchlist

GET

/v1/watchlists

List watchlists

GET

/v1/watchlists/{id}

Get a watchlist

PATCH

/v1/watchlists/{id}

Update a watchlist

DELETE

/v1/watchlists/{id}

Delete a watchlist

POST

/v1/watchlists/{id}/run

Run a watchlist now

GET

/v1/watchlists/scrapers

List pipeline scrapers

GET

/v1/watchlists/{id}/runs

List runs

GET

/v1/watchlists/{id}/items

List items

POST

/v1/watchlists/{id}/items

Add or remove items

POST

/v1/watchlists/{id}/asins

Add or remove items (legacy path) (deprecated)

How it works, when to use what, and what it costs: Watchlists & pipelines. Base URL, authentication and errors: Overview.

POST /v1/watchlists

Create a watchlist.

Track up to 50,000 items of one platform and marketplace on a cadence (every) or a cron schedule in a time zone (cron + timezone) (at most 100 lists per account). Creating is free. Send the item ids in ids (every platform); asins is still accepted on Amazon as a legacy alias. Send a pipeline to choose the scrapers each run uses and how they chain; without one the platform default runs. The first run starts at once and reads every item at the baseline step (default on Amazon: full; no change events). With the default pipeline, on Amazon each later run sweeps at pulse, escalates to lite the ASINs whose offer count or lowest new price moved (plus those whose buy box sat above the lowest offer, and any owed retry), and every refresh_every_runs-th run sweeps everything at lite; one-tier retailers fetch and diff every item each run. Runs are billed exactly like the /v1/products calls they make; a run the balance cannot cover is skipped (insufficient_credits), and the third skip in a row pauses the list.

Headers

Name

Type

Required

Description

Idempotency-Key

string

—

Retrying with the same key returns the original response (Idempotent-Replayed: true) instead of creating a second list. Remembered 24 hours. Up to 255 characters.

Request body

Name

Type

Required

Description

name

string

yes

Up to 100 characters.

ids

string[]

yes

1 to 50,000 item ids of platform (ASINs, item ids, TCINs, SKUs…; de-duplicated). A newline- or comma-separated string is also accepted.

asins

string[]

—

Deprecated. Amazon only, legacy: the same as ids (ASINs are case-insensitive). Send ids or asins, not both. At most 50,000 items.

every

string

—

Cadence, start to start: whole minutes, hours or days, at least 5 minutes, at most 7 days. E.g. 5m, 15m, 1h, 6h, 24h. Send this or cron.

cron

string

—

Standard 5-field cron (minute hour day-of-month month day-of-week) read in timezone: *, lists (1,15), ranges (9-17), steps (*/15, 0-30/10), names (JAN-DEC, SUN-SAT; 0 and 7 are Sunday), and @hourly, @daily, @weekly, @monthly, @yearly. No seconds. When both day fields are restricted a day matches either (Vixie cron). Must not fire more often than every 5 minutes. Across DST a skipped local time runs once, shifted forward by the gap, and a repeated one runs once, at its first occurrence. Send this or every.

timezone

string

—

IANA time zone the cron is read in, e.g. America/New_York, Europe/London. Default UTC. Only with cron.

webhook_url

string

—

One of your registered webhook endpoints (/v1/webhook_endpoints), by URL: this list's events go there only, signed with that endpoint's secret. An unregistered URL is a 400. Omitted: every endpoint subscribed to each event.

webhook_endpoint_id

string

—

Alternative to webhook_url: the endpoint's id (we_…). Send one or the other.

refresh_every_runs

integer

—

Default pipeline on Amazon: every Nth run sweeps every ASIN at lite instead of pulse (sees buy-box seller changes at the same price; refreshes offer listing ids). 0 = never. A custom pipeline sets this with refresh. From 0 to 1,000.

pipeline

object

—

What each run does. Omitted: the platform default.

pipeline.entry

string

—

The step every run starts with. Default: the first step.

pipeline.baseline

string or null

—

Where items never read before start instead. Default: entry.

pipeline.refresh

object or null

—

Every Nth run starts at this step instead.

pipeline.refresh.every_runs

integer

yes

From 1 to 1,000.

pipeline.refresh.entry

string

yes

—

pipeline.steps

object[]

yes

1 to 10 items.

pipeline.steps[].id

string

yes

—

pipeline.steps[].scraper

string

yes

GET /v1/watchlists/scrapers lists them with their fields. One of: amazon.pulse, amazon.lite, amazon.full, amazon.offers, amazon.offer_check, walmart.standard, target.standard, bestbuy.standard.

pipeline.steps[].condition

string

—

amazon.offers only. One of: all, new, used.

pipeline.steps[].routes

object[]

—

At most 8 items.

pipeline.steps[].routes[].when

string

yes

One of: new, changed, unchanged, ok, failed, not_found, always.

pipeline.steps[].routes[].field

string

—

With changed: only this field counts. With ok: the field op tests.

pipeline.steps[].routes[].op

string

—

One of: increased, decreased, below, above, is, is_not.

pipeline.steps[].routes[].value

number or boolean or string

—

—

pipeline.steps[].routes[].run

string

—

A step id to run next for the matching items.

pipeline.steps[].routes[].notify

boolean

—

Send the matching items (changed: watchlist.product.changed; else watchlist.product.matched).

platform

string

—

Which platform to read. Platforms: amazon (live: us; coming soon: uk, de, fr, it, es, ca, mx, jp, au, in, br, nl, se, pl), walmart (live: us), ebay (coming soon), target (live: us), bestbuy (live: us; coming soon: ca), aliexpress (coming soon). A coming-soon platform or marketplace answers 501 NOT_IMPLEMENTED with "coming_soon": true (nothing charged); an unknown one is a 400 listing the valid values. GET /v1/platforms has the full list. Default amazon.

marketplace

string

—

The platform's regional storefront (us, uk, de…); default the platform's main one. Prices come back in its currency.

Request

curl -X POST "https://api.scrapelyserp.com/v1/watchlists" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Consoles",
    "platform": "target",
    "marketplace": "us",
    "ids": ["83887639", "1011697103"],
    "every": "15m",
    "webhook_url": "https://example.com/hooks/scrapely"
  }'

Response

{
  "id": "wl_3f1c2a9e8d4b4c61",
  "object": "watchlist",
  "name": "Consoles",
  "platform": "target",
  "marketplace": "us",
  "currency": "USD",
  "status": "active",
  "paused_reason": null,
  "schedule": {
    "type": "every",
    "every": "15m",
    "every_seconds": 900
  },
  "every": "15m",
  "every_seconds": 900,
  "refresh_every_runs": 8,
  "webhook_url": "https://example.com/hooks/scrapely",
  "item_count": 2,
  "items_by_state": {
    "new": 2,
    "active": 0,
    "delisted": 0
  },
  "asin_count": 2,
  "asins_by_state": {
    "new": 2,
    "active": 0,
    "delisted": 0
  },
  "pipeline": {
    "entry": "check",
    "baseline": null,
    "refresh": null,
    "steps": [
      {
        "id": "check",
        "scraper": "target.standard",
        "routes": [
          {
            "when": "changed",
            "notify": true
          }
        ]
      }
    ]
  },
  "default_pipeline": true,
  "estimated_credits": {
    "pulseRun": 0,
    "refreshRun": 0,
    "newAsins": 2
  },
  "run_count": 0,
  "consecutive_skips": 0,
  "last_run_at": null,
  "last_run_status": null,
  "next_run_at": "2026-10-16T09:15:04.120Z",
  "created_at": "2026-10-16T09:15:04.120Z",
  "updated_at": "2026-10-16T09:15:04.120Z",
  "url": "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61"
}

Responses

Status

Meaning

201

Created; the first run is due now.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

403

DEMO_READ_ONLY.

409

CONFLICT: idempotent request in flight, a run already in progress, or a per-account limit.

422

INVALID_PARAM with param: idempotency_key: the key was used for a different request.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist"

—

name

string

—

platform

string

Whose item ids the list holds (id on each item).

marketplace

string

Every run fetches the list here.

currency

string

The currency of every price in its snapshots, changes and webhooks.

status

string

One of: active, paused.

paused_reason

string or null

One of: user, insufficient_credits.

schedule

object or object

When the list runs: a cadence (start to start) or a cron schedule in a time zone.

every

string or null

The cadence of an every-list; null on a cron list (see schedule).

every_seconds

integer or null

The cadence in seconds; null on a cron list.

refresh_every_runs

integer

—

pipeline

object

Up to 10 steps, each running one scraper over the items sent to it; its routes send the items on a branch to another step (run), the webhook (notify), or both. Chains cannot loop.

pipeline.entry

string

The step every run starts with. Default: the first step.

pipeline.baseline

string or null

Where items never read before start instead. Default: entry.

pipeline.refresh

object or null

Every Nth run starts at this step instead.

pipeline.steps

object[]

1 to 10 items.

default_pipeline

boolean

True when the list runs its platform default.

webhook_url

string or null

—

item_count

integer

Items on the list, every state.

items_by_state

object

—

items_by_state.new

integer

—

items_by_state.active

integer

—

items_by_state.delisted

integer

—

asin_count

integer

Deprecated. Deprecated alias, same value as item_count (every platform).

asins_by_state

object

Deprecated. Deprecated alias, same value as items_by_state (every platform).

asins_by_state.new

integer

—

asins_by_state.active

integer

—

asins_by_state.delisted

integer

—

estimated_credits

object

Up-front cost of the next runs: a sweep run with nothing changed (Amazon: pulse), a refresh run, and the one-off baseline fetch of new items (newAsins, on every platform). On Amazon, escalations add lite credits per moved ASIN.

estimated_credits.pulseRun

integer

—

estimated_credits.refreshRun

integer

—

estimated_credits.newAsins

integer

—

run_count

integer

—

consecutive_skips

integer

Runs skipped in a row for credits; the third pauses the list.

last_run_at

string (date-time) or null

—

last_run_status

string or null

One of: running, completed, insufficient_credits, failed.

next_run_at

string (date-time) or null

null while paused.

created_at

string (date-time)

—

updated_at

string (date-time)

—

url

string

—

GET /v1/watchlists

List watchlists.

Your watchlists, newest first, with their schedule, pipeline and last run. Free.

Query parameters

Name

Type

Required

Description

limit

integer

—

How many lists to return. Default 100. From 1 to 100.

Request

curl -G "https://api.scrapelyserp.com/v1/watchlists" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -d limit=20

Response

{
  "object": "list",
  "data": [
    {
      "id": "wl_3f1c2a9e8d4b4c61",
      "object": "watchlist",
      "name": "Consoles",
      "platform": "target",
      "marketplace": "us",
      "currency": "USD",
      "status": "active",
      "paused_reason": null,
      "schedule": {
        "type": "every",
        "every": "15m",
        "every_seconds": 900
      },
      "every": "15m",
      "every_seconds": 900,
      "refresh_every_runs": 8,
      "webhook_url": "https://example.com/hooks/scrapely",
      "item_count": 2,
      "items_by_state": {
        "new": 0,
        "active": 2,
        "delisted": 0
      },
      "asin_count": 2,
      "asins_by_state": {
        "new": 0,
        "active": 2,
        "delisted": 0
      },
      "pipeline": {
        "entry": "check",
        "baseline": null,
        "refresh": null,
        "steps": [
          {
            "id": "check",
            "scraper": "target.standard",
            "routes": [
              {
                "when": "changed",
                "notify": true
              }
            ]
          }
        ]
      },
      "default_pipeline": true,
      "estimated_credits": {
        "pulseRun": 2,
        "refreshRun": 2,
        "newAsins": 0
      },
      "run_count": 42,
      "consecutive_skips": 0,
      "last_run_at": "2026-10-16T09:15:00.004Z",
      "last_run_status": "completed",
      "next_run_at": "2026-10-16T09:30:00.004Z",
      "created_at": "2026-10-06T08:00:00.000Z",
      "updated_at": "2026-10-16T09:15:21.101Z",
      "url": "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61"
    }
  ],
  "has_more": false
}

Responses

Status

Meaning

200

Newest first.

401

UNAUTHORIZED: missing, unknown or revoked key.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"list"

—

data

object[]

—

data[].id

string

—

data[].object

"watchlist"

—

data[].name

string

—

data[].platform

string

Whose item ids the list holds (id on each item).

data[].marketplace

string

Every run fetches the list here.

data[].currency

string

The currency of every price in its snapshots, changes and webhooks.

data[].status

string

One of: active, paused.

data[].paused_reason

string or null

One of: user, insufficient_credits.

data[].schedule

object or object

When the list runs: a cadence (start to start) or a cron schedule in a time zone.

data[].every

string or null

The cadence of an every-list; null on a cron list (see schedule).

data[].every_seconds

integer or null

The cadence in seconds; null on a cron list.

data[].refresh_every_runs

integer

—

data[].pipeline

object

Up to 10 steps, each running one scraper over the items sent to it; its routes send the items on a branch to another step (run), the webhook (notify), or both. Chains cannot loop.

data[].default_pipeline

boolean

True when the list runs its platform default.

data[].webhook_url

string or null

—

data[].item_count

integer

Items on the list, every state.

data[].items_by_state

object

—

data[].asin_count

integer

Deprecated. Deprecated alias, same value as item_count (every platform).

data[].asins_by_state

object

Deprecated. Deprecated alias, same value as items_by_state (every platform).

data[].estimated_credits

object

Up-front cost of the next runs: a sweep run with nothing changed (Amazon: pulse), a refresh run, and the one-off baseline fetch of new items (newAsins, on every platform). On Amazon, escalations add lite credits per moved ASIN.

data[].run_count

integer

—

data[].consecutive_skips

integer

Runs skipped in a row for credits; the third pauses the list.

data[].last_run_at

string (date-time) or null

—

data[].last_run_status

string or null

One of: running, completed, insufficient_credits, failed.

data[].next_run_at

string (date-time) or null

null while paused.

data[].created_at

string (date-time)

—

data[].updated_at

string (date-time)

—

data[].url

string

—

has_more

boolean

—

GET /v1/watchlists/{id}

Get a watchlist.

One list, with its item counts per state (items_by_state) and the credits its next runs should cost (estimated_credits). Free.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request

curl "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "id": "wl_3f1c2a9e8d4b4c61",
  "object": "watchlist",
  "name": "Consoles",
  "platform": "target",
  "marketplace": "us",
  "currency": "USD",
  "status": "active",
  "paused_reason": null,
  "schedule": {
    "type": "every",
    "every": "15m",
    "every_seconds": 900
  },
  "every": "15m",
  "every_seconds": 900,
  "refresh_every_runs": 8,
  "webhook_url": "https://example.com/hooks/scrapely",
  "item_count": 2,
  "items_by_state": {
    "new": 0,
    "active": 2,
    "delisted": 0
  },
  "asin_count": 2,
  "asins_by_state": {
    "new": 0,
    "active": 2,
    "delisted": 0
  },
  "pipeline": {
    "entry": "check",
    "baseline": null,
    "refresh": null,
    "steps": [
      {
        "id": "check",
        "scraper": "target.standard",
        "routes": [
          {
            "when": "changed",
            "notify": true
          }
        ]
      }
    ]
  },
  "default_pipeline": true,
  "estimated_credits": {
    "pulseRun": 2,
    "refreshRun": 2,
    "newAsins": 0
  },
  "run_count": 42,
  "consecutive_skips": 0,
  "last_run_at": "2026-10-16T09:15:00.004Z",
  "last_run_status": "completed",
  "next_run_at": "2026-10-16T09:30:00.004Z",
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-16T09:15:21.101Z",
  "url": "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61"
}

Responses

Status

Meaning

200

The watchlist, with item counts per state and credit estimates.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist"

—

name

string

—

platform

string

Whose item ids the list holds (id on each item).

marketplace

string

Every run fetches the list here.

currency

string

The currency of every price in its snapshots, changes and webhooks.

status

string

One of: active, paused.

paused_reason

string or null

One of: user, insufficient_credits.

schedule

object or object

When the list runs: a cadence (start to start) or a cron schedule in a time zone.

every

string or null

The cadence of an every-list; null on a cron list (see schedule).

every_seconds

integer or null

The cadence in seconds; null on a cron list.

refresh_every_runs

integer

—

pipeline

object

Up to 10 steps, each running one scraper over the items sent to it; its routes send the items on a branch to another step (run), the webhook (notify), or both. Chains cannot loop.

pipeline.entry

string

The step every run starts with. Default: the first step.

pipeline.baseline

string or null

Where items never read before start instead. Default: entry.

pipeline.refresh

object or null

Every Nth run starts at this step instead.

pipeline.steps

object[]

1 to 10 items.

default_pipeline

boolean

True when the list runs its platform default.

webhook_url

string or null

—

item_count

integer

Items on the list, every state.

items_by_state

object

—

items_by_state.new

integer

—

items_by_state.active

integer

—

items_by_state.delisted

integer

—

asin_count

integer

Deprecated. Deprecated alias, same value as item_count (every platform).

asins_by_state

object

Deprecated. Deprecated alias, same value as items_by_state (every platform).

asins_by_state.new

integer

—

asins_by_state.active

integer

—

asins_by_state.delisted

integer

—

estimated_credits

object

Up-front cost of the next runs: a sweep run with nothing changed (Amazon: pulse), a refresh run, and the one-off baseline fetch of new items (newAsins, on every platform). On Amazon, escalations add lite credits per moved ASIN.

estimated_credits.pulseRun

integer

—

estimated_credits.refreshRun

integer

—

estimated_credits.newAsins

integer

—

run_count

integer

—

consecutive_skips

integer

Runs skipped in a row for credits; the third pauses the list.

last_run_at

string (date-time) or null

—

last_run_status

string or null

One of: running, completed, insufficient_credits, failed.

next_run_at

string (date-time) or null

null while paused.

created_at

string (date-time)

—

updated_at

string (date-time)

—

url

string

—

PATCH /v1/watchlists/{id}

Update a watchlist.

Rename; switch between a cadence (every, counted from the last run) and a cron schedule (cron + timezone); change the webhook, the pipeline or the refresh interval; pause or resume. Send only the fields to change. Free.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request body

Name

Type

Required

Description

name

string

—

Up to 100 characters.

every

string

—

Switch to (or change) a cadence; clears a cron schedule. Send this or cron.

cron

string

—

Switch to (or change) a cron schedule. Standard 5-field cron (minute hour day-of-month month day-of-week) read in timezone: *, lists (1,15), ranges (9-17), steps (*/15, 0-30/10), names (JAN-DEC, SUN-SAT; 0 and 7 are Sunday), and @hourly, @daily, @weekly, @monthly, @yearly. No seconds. When both day fields are restricted a day matches either (Vixie cron). Must not fire more often than every 5 minutes. Across DST a skipped local time runs once, shifted forward by the gap, and a repeated one runs once, at its first occurrence. Send this or every.

timezone

string

—

With cron: its zone (omitted: the list keeps its zone, UTC for a list switching from every). Alone: re-zone an existing cron schedule (400 on an every-list).

webhook_url

string or null

—

A registered endpoint URL; null clears it (events go to every subscribed endpoint).

webhook_endpoint_id

string or null

—

Alternative to webhook_url: a registered endpoint's id.

refresh_every_runs

integer

—

From 0 to 1,000.

pipeline

object or null

—

null goes back to the platform default. Each item keeps what it last showed.

pipeline.entry

string

—

The step every run starts with. Default: the first step.

pipeline.baseline

string or null

—

Where items never read before start instead. Default: entry.

pipeline.refresh

object or null

—

Every Nth run starts at this step instead.

pipeline.refresh.every_runs

integer

yes

From 1 to 1,000.

pipeline.refresh.entry

string

yes

—

pipeline.steps

object[]

yes

1 to 10 items.

pipeline.steps[].id

string

yes

—

pipeline.steps[].scraper

string

yes

GET /v1/watchlists/scrapers lists them with their fields. One of: amazon.pulse, amazon.lite, amazon.full, amazon.offers, amazon.offer_check, walmart.standard, target.standard, bestbuy.standard.

pipeline.steps[].condition

string

—

amazon.offers only. One of: all, new, used.

pipeline.steps[].routes

object[]

—

At most 8 items.

pipeline.steps[].routes[].when

string

yes

One of: new, changed, unchanged, ok, failed, not_found, always.

pipeline.steps[].routes[].field

string

—

With changed: only this field counts. With ok: the field op tests.

pipeline.steps[].routes[].op

string

—

One of: increased, decreased, below, above, is, is_not.

pipeline.steps[].routes[].value

number or boolean or string

—

—

pipeline.steps[].routes[].run

string

—

A step id to run next for the matching items.

pipeline.steps[].routes[].notify

boolean

—

Send the matching items (changed: watchlist.product.changed; else watchlist.product.matched).

status

string

—

Resuming clears an auto-pause and its skip count. One of: active, paused.

Request

curl -X PATCH "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cron":"0 8 * * 1-5","timezone":"America/New_York"}'

Response

{
  "id": "wl_3f1c2a9e8d4b4c61",
  "object": "watchlist",
  "name": "Consoles",
  "platform": "target",
  "marketplace": "us",
  "currency": "USD",
  "status": "active",
  "paused_reason": null,
  "schedule": {
    "type": "cron",
    "cron": "0 8 * * 1-5",
    "timezone": "America/New_York"
  },
  "every": null,
  "every_seconds": null,
  "refresh_every_runs": 8,
  "webhook_url": "https://example.com/hooks/scrapely",
  "item_count": 2,
  "items_by_state": {
    "new": 0,
    "active": 2,
    "delisted": 0
  },
  "asin_count": 2,
  "asins_by_state": {
    "new": 0,
    "active": 2,
    "delisted": 0
  },
  "pipeline": {
    "entry": "check",
    "baseline": null,
    "refresh": null,
    "steps": [
      {
        "id": "check",
        "scraper": "target.standard",
        "routes": [
          {
            "when": "changed",
            "notify": true
          }
        ]
      }
    ]
  },
  "default_pipeline": true,
  "estimated_credits": {
    "pulseRun": 2,
    "refreshRun": 2,
    "newAsins": 0
  },
  "run_count": 42,
  "consecutive_skips": 0,
  "last_run_at": "2026-10-16T09:15:00.004Z",
  "last_run_status": "completed",
  "next_run_at": "2026-10-19T12:00:00.000Z",
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-16T09:15:04.120Z",
  "url": "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61"
}

Responses

Status

Meaning

200

Updated.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist"

—

name

string

—

platform

string

Whose item ids the list holds (id on each item).

marketplace

string

Every run fetches the list here.

currency

string

The currency of every price in its snapshots, changes and webhooks.

status

string

One of: active, paused.

paused_reason

string or null

One of: user, insufficient_credits.

schedule

object or object

When the list runs: a cadence (start to start) or a cron schedule in a time zone.

every

string or null

The cadence of an every-list; null on a cron list (see schedule).

every_seconds

integer or null

The cadence in seconds; null on a cron list.

refresh_every_runs

integer

—

pipeline

object

Up to 10 steps, each running one scraper over the items sent to it; its routes send the items on a branch to another step (run), the webhook (notify), or both. Chains cannot loop.

pipeline.entry

string

The step every run starts with. Default: the first step.

pipeline.baseline

string or null

Where items never read before start instead. Default: entry.

pipeline.refresh

object or null

Every Nth run starts at this step instead.

pipeline.steps

object[]

1 to 10 items.

default_pipeline

boolean

True when the list runs its platform default.

webhook_url

string or null

—

item_count

integer

Items on the list, every state.

items_by_state

object

—

items_by_state.new

integer

—

items_by_state.active

integer

—

items_by_state.delisted

integer

—

asin_count

integer

Deprecated. Deprecated alias, same value as item_count (every platform).

asins_by_state

object

Deprecated. Deprecated alias, same value as items_by_state (every platform).

asins_by_state.new

integer

—

asins_by_state.active

integer

—

asins_by_state.delisted

integer

—

estimated_credits

object

Up-front cost of the next runs: a sweep run with nothing changed (Amazon: pulse), a refresh run, and the one-off baseline fetch of new items (newAsins, on every platform). On Amazon, escalations add lite credits per moved ASIN.

estimated_credits.pulseRun

integer

—

estimated_credits.refreshRun

integer

—

estimated_credits.newAsins

integer

—

run_count

integer

—

consecutive_skips

integer

Runs skipped in a row for credits; the third pauses the list.

last_run_at

string (date-time) or null

—

last_run_status

string or null

One of: running, completed, insufficient_credits, failed.

next_run_at

string (date-time) or null

null while paused.

created_at

string (date-time)

—

updated_at

string (date-time)

—

url

string

—

DELETE /v1/watchlists/{id}

Delete a watchlist.

Deletes the list, its items and its run history. A run already in progress finishes but sends no webhooks.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request

curl -X DELETE "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "id": "wl_3f1c2a9e8d4b4c61",
  "object": "watchlist",
  "deleted": true
}

Responses

Status

Meaning

200

Deleted.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist"

—

deleted

true

—

POST /v1/watchlists/{id}/run

Run a watchlist now.

Starts a run at once (202). A cadence list (every) counts its next run from now; a cron list keeps its wall-clock times, skipping a fire time less than 5 minutes after the manual run. Billed like a scheduled run; works on a paused list. 409 while a run of this list is in progress.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request

curl -X POST "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61/run" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "id": "wlrun_5f0c8a1b2d3e4f56",
  "object": "watchlist_run",
  "watchlist_id": "wl_3f1c2a9e8d4b4c61",
  "run_number": 42,
  "trigger": "manual",
  "kind": "sweep",
  "status": "running",
  "credits": 0,
  "stats": null,
  "error": null,
  "started_at": "2026-10-16T09:15:04.120Z",
  "finished_at": null,
  "runs_url": "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61/runs"
}

Responses

Status

Meaning

202

Started.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

409

CONFLICT: idempotent request in flight, a run already in progress, or a per-account limit.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist_run"

—

watchlist_id

string

—

run_number

integer

—

trigger

string

One of: schedule, manual.

kind

string

sweep: a regular run from the pipeline's entry step. refresh: every Nth run, from the refresh entry (refresh_every_runs). One of: sweep, refresh.

status

string

One of: running, completed, insufficient_credits, failed.

credits

integer

Charged, after refunds.

stats

object or null

—

stats.tracked

integer

—

stats.entry

string

The step the run started from.

stats.new_items

integer

Items read for the first time.

stats.steps

object

Per step that ran, in run order.

stats.matched

integer

Items a notify rule matched on a branch other than changed.

stats.sweep_tier

string

Deprecated. Runs before pipelines. Amazon: pulse, or lite on a refresh run. One-tier platforms: their one tier.

stats.calls

object

Deprecated. Runs before pipelines, keyed by tier.

stats.escalated

object

Deprecated.

stats.deferred

integer

Step items postponed to the next run: the balance could not cover them.

stats.changed

integer

—

stats.delisted

integer

—

stats.retry_next_run

integer

partial + unavailable items (free, retried next run, never a change).

stats.credits_needed

integer

On insufficient_credits: what the run needed up front.

error

string or null

—

started_at

string (date-time)

—

finished_at

string (date-time) or null

—

runs_url

string

—

GET /v1/watchlists/scrapers

List pipeline scrapers.

What a pipeline step can run on a platform: each scraper, what it reads, its credits per item, the fields its routes can test and whether it is available in the marketplace; plus ready-made templates. Free.

Query parameters

Name

Type

Required

Description

platform

string

—

The platform whose scrapers to list. Default amazon.

marketplace

string

—

Marks each scraper available or not in this marketplace. Default us.

Request

curl -G "https://api.scrapelyserp.com/v1/watchlists/scrapers" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -d platform=walmart \
  -d marketplace=us

Response

{
  "object": "list",
  "platform": "walmart",
  "marketplace": "us",
  "branches": ["new", "changed", "unchanged", "ok", "failed", "not_found", "always"],
  "ops": ["increased", "decreased", "below", "above", "is", "is_not"],
  "data": [
    {
      "id": "walmart.standard",
      "name": "Product lookup",
      "description": "Price, stock and the rest of what the retailer shows.",
      "credits_per_item": "1",
      "reads": "product",
      "input": "item",
      "fields": [
        {
          "key": "price",
          "label": "Price",
          "type": "money"
        },
        {
          "key": "listPrice",
          "label": "List price",
          "type": "money"
        },
        {
          "key": "inStock",
          "label": "In stock",
          "type": "boolean"
        },
        {
          "key": "seller",
          "label": "Seller",
          "type": "text"
        },
        {
          "key": "byPlatform",
          "label": "Sold by Walmart",
          "type": "boolean"
        },
        {
          "key": "clearance",
          "label": "Clearance",
          "type": "boolean"
        }
      ],
      "available": true
    }
  ],
  "templates": [
    {
      "id": "default",
      "name": "Price & stock monitor",
      "description": "Notify when price, stock or seller changes.",
      "pipeline": {
        "entry": "check",
        "baseline": null,
        "refresh": null,
        "steps": [
          {
            "id": "check",
            "scraper": "walmart.standard",
            "routes": [
              {
                "when": "changed",
                "notify": true
              }
            ]
          }
        ]
      }
    },
    {
      "id": "restock",
      "name": "Back in stock",
      "description": "Notify only when an item comes back in stock.",
      "pipeline": {
        "entry": "check",
        "baseline": null,
        "refresh": null,
        "steps": [
          {
            "id": "check",
            "scraper": "walmart.standard",
            "routes": [
              {
                "when": "changed",
                "field": "inStock",
                "op": "is",
                "value": true,
                "notify": true
              }
            ]
          }
        ]
      }
    },
    {
      "id": "price-drop",
      "name": "Price drops",
      "description": "Notify when the price goes down.",
      "pipeline": {
        "entry": "check",
        "baseline": null,
        "refresh": null,
        "steps": [
          {
            "id": "check",
            "scraper": "walmart.standard",
            "routes": [
              {
                "when": "changed",
                "field": "price",
                "op": "decreased",
                "notify": true
              }
            ]
          }
        ]
      }
    }
  ]
}

Responses

Status

Meaning

200

Scrapers and templates.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"list"

—

platform

string

—

marketplace

string

—

branches

string[]

—

ops

string[]

—

data

object[]

—

data[].id

string

The scraper value of a pipeline step.

data[].name

string

—

data[].description

string

—

data[].credits_per_item

string

A number, or a range such as 1–3 when it depends on the answer.

data[].reads

string

The kind of data it reads; steps of one kind compare with each other. One of: pulse, product, offers, offer_check.

data[].input

string

offer: needs the buy-box offer an earlier product or offers step found. One of: item, offer.

data[].fields

object[]

What rules can test (field).

data[].options

object

Step options, when it has any: condition for amazon.offers.

data[].available

boolean

Can run in marketplace.

templates

object[]

—

templates[].id

string

—

templates[].name

string

—

templates[].description

string

—

templates[].pipeline

object

Up to 10 steps, each running one scraper over the items sent to it; its routes send the items on a branch to another step (run), the webhook (notify), or both. Chains cannot loop.

GET /v1/watchlists/{id}/runs

List runs.

The list's runs, newest first, with per-step counts and the credits each run cost. The newest 500 are kept. Free.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Query parameters

Name

Type

Required

Description

limit

integer

—

How many runs to return. Default 20. From 1 to 100.

Request

curl -G "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61/runs" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -d limit=20

Response

{
  "object": "list",
  "data": [
    {
      "id": "wlrun_5f0c8a1b2d3e4f56",
      "object": "watchlist_run",
      "watchlist_id": "wl_3f1c2a9e8d4b4c61",
      "run_number": 42,
      "trigger": "schedule",
      "kind": "sweep",
      "status": "completed",
      "credits": 2,
      "stats": {
        "tracked": 2,
        "entry": "check",
        "new_items": 0,
        "steps": {
          "check": {
            "scraper": "target.standard",
            "requested": 2,
            "ok": 2,
            "partial": 0,
            "not_found": 0,
            "unavailable": 0,
            "credits": 2,
            "skipped": 0
          }
        },
        "matched": 0,
        "deferred": 0,
        "changed": 1,
        "delisted": 0,
        "retry_next_run": 0
      },
      "error": null,
      "started_at": "2026-10-16T09:15:00.004Z",
      "finished_at": "2026-10-16T09:15:02.310Z"
    }
  ],
  "has_more": true
}

Responses

Status

Meaning

200

Runs.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"list"

—

data

object[]

—

data[].id

string

—

data[].object

"watchlist_run"

—

data[].watchlist_id

string

—

data[].run_number

integer

—

data[].trigger

string

One of: schedule, manual.

data[].kind

string

sweep: a regular run from the pipeline's entry step. refresh: every Nth run, from the refresh entry (refresh_every_runs). One of: sweep, refresh.

data[].status

string

One of: running, completed, insufficient_credits, failed.

data[].credits

integer

Charged, after refunds.

data[].stats

object or null

—

data[].error

string or null

—

data[].started_at

string (date-time)

—

data[].finished_at

string (date-time) or null

—

has_more

boolean

—

GET /v1/watchlists/{id}/items

List items.

The items on the list with their last snapshot, in id order. Each carries id (plus asin on Amazon lists). changed_since returns only items that changed or were delisted since then: the pull counterpart of the webhook.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Query parameters

Name

Type

Required

Description

changed_since

string

—

ISO 8601 or epoch milliseconds.

state

string

—

Only items in this state. One of: new, active, delisted.

limit

integer

—

Items per page. Default 100. From 1 to 1,000.

starting_after

string

—

next_starting_after from the previous page.

Request

curl -G "https://api.scrapelyserp.com/v1/watchlists/wl_3f1c2a9e8d4b4c61/items" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  --data-urlencode "changed_since=2026-10-15T09:00:00Z" \
  -d limit=100

Response

{
  "object": "list",
  "platform": "target",
  "marketplace": "us",
  "data": [
    {
      "id": "83887639",
      "state": "active",
      "added_at": "2026-10-06T08:00:00.000Z",
      "last_status": "ok",
      "pulse": null,
      "snapshot": {
        "price": 349.99,
        "regularPrice": 399.99,
        "inStock": true,
        "shipping": "IN_STOCK",
        "pickup": "IN_STOCK",
        "title": "Nintendo Switch - OLED Model with White Joy-Con",
        "parentTcin": null
      },
      "snapshot_at": "2026-10-16T09:15:01.870Z",
      "snapshot_tier": "standard",
      "buybox_above_lowest": false,
      "pending_standard": false,
      "changed_at": "2026-10-16T09:15:01.870Z",
      "last_change": {
        "price": {
          "before": 399.99,
          "after": 349.99
        }
      },
      "delisted_at": null
    }
  ],
  "has_more": false,
  "next_starting_after": "83887639"
}

Responses

Status

Meaning

200

A page of items.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"list"

—

platform

string

—

marketplace

string

—

data

object[]

—

data[].id

string

The item's id on the list's platform: an ASIN on Amazon, an item id on Walmart, a TCIN on Target, a SKU on Best Buy.

data[].asin

string

Deprecated. Amazon lists only: the same value as id, kept for clients written before platforms. Absent on every other platform.

data[].state

string

new: waiting for its first (baseline) fetch. delisted: the retailer said not_found; never fetched again (add it again to retry). One of: new, active, delisted.

data[].added_at

string (date-time)

—

data[].last_status

string or null

One of: ok, partial, not_found, unavailable.

data[].pulse

object or null

—

data[].snapshot

object or null

The tracked fields from the last detail fetch, named as in /v1/products results (each platform tracks its own; these are Amazon's). null = the retailer did not say.

data[].snapshot_at

string (date-time) or null

—

data[].snapshot_tier

string or null

The tier the snapshot came from (Amazon: lite or full).

data[].buybox_above_lowest

boolean

The buy box cost more than the lowest new offer at the last fetch, so every run checks it at lite.

data[].pending_standard

boolean

A detail fetch (Amazon: lite) is owed: pulse moved, or the last one failed or was deferred.

data[].changed_at

string (date-time) or null

—

data[].last_change

object or null

—

data[].delisted_at

string (date-time) or null

—

has_more

boolean

—

next_starting_after

string or null

The last id of this page.

POST /v1/watchlists/{id}/items

Add or remove items.

Item ids of the list's platform. Removals apply first. Added items get a baseline fetch on the next run (Amazon: full; no change event); a delisted item added again gets another chance. At most 50,000 items per list. Free.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request body

Name

Type

Required

Description

add

string[]

—

Item ids to add. At most 50,000 items.

remove

string[]

—

Item ids to remove. At most 50,000 items.

Request

curl -X POST "https://api.scrapelyserp.com/v1/watchlists/wl_9a8b7c6d5e4f3a21/items" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"add":["6505727"],"remove":["6418599"]}'

Response

{
  "id": "wl_9a8b7c6d5e4f3a21",
  "object": "watchlist_items",
  "platform": "bestbuy",
  "marketplace": "us",
  "added": 1,
  "reactivated": 0,
  "removed": 1,
  "unchanged": 0,
  "item_count": 120,
  "asin_count": 120
}

Responses

Status

Meaning

200

What changed.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist_items"

—

platform

string

—

marketplace

string

—

added

integer

—

reactivated

integer

Delisted items added again.

removed

integer

—

unchanged

integer

Already present (add) or not present (remove).

item_count

integer

—

asin_count

integer

Deprecated. Deprecated alias, same value as item_count.

POST /v1/watchlists/{id}/asins

Add or remove items (legacy path).

Deprecated

Still answered exactly as documented, but kept only for older clients. New code should use the replacement named below.

The historical path of POST /api/v1/watchlists/{id}/items: same body and behaviour on every platform; only object differs. Item ids of the list's platform. Removals apply first. Added items get a baseline fetch on the next run (Amazon: full; no change event); a delisted item added again gets another chance. At most 50,000 items per list. Free.

Path parameters

Name

Type

Required

Description

id

string

yes

The watchlist id (wl_…).

Request body

Name

Type

Required

Description

add

string[]

—

Item ids to add. At most 50,000 items.

remove

string[]

—

Item ids to remove. At most 50,000 items.

Request

curl -X POST "https://api.scrapelyserp.com/v1/watchlists/wl_2b3c4d5e6f7a8b9c/asins" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"add":["B074PVTPBW"],"remove":["0060094664"]}'

Response

{
  "id": "wl_2b3c4d5e6f7a8b9c",
  "object": "watchlist_asins",
  "platform": "amazon",
  "marketplace": "us",
  "added": 1,
  "reactivated": 0,
  "removed": 1,
  "unchanged": 0,
  "item_count": 2400,
  "asin_count": 2400
}

Responses

Status

Meaning

200

What changed.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"watchlist_asins"

—

platform

string

—

marketplace

string

—

added

integer

—

reactivated

integer

Delisted items added again.

removed

integer

—

unchanged

integer

Already present (add) or not present (remove).

item_count

integer

—

asin_count

integer

Deprecated. Deprecated alias, same value as item_count.

Updated