Pricewatcha API
MCP serverMonitoring & opsPricewatcha lets your AI keep an eye on prices across online shops. Once added, your AI can check what an item costs today, look up how its price has changed over time, and alert you when prices move.
Use Pricewatcha API in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Pricewatcha API and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use Pricewatcha API to get api status
No key or account is asked for. Not verified by us yet: Ahel has not run a call through it.
Details
Available today. Use it from your connected AI after setup.
No key or account is asked for. Not verified by us yet: Ahel has not run a call through it.
Add Pricewatcha, then tell your AI which products or shops you want it to watch. It will start tracking prices and alert you when they change.
What your AI can do with it
- Check the current price of a product on any online shop
- Look up how a product's price has changed over time
- Get alerts when prices change
- Track prices on any online shop
Install Pricewatcha API
The server’s own address, for the clients that take one directly. Or connect Ahel once and every client you use reads it from one address, with the account kept on Ahel rather than in each client’s config.
Claude Code
claude mcp add --transport http --scope user pricewatcha-api 'https://mcp.pricewatcha.com'Run it once in your project, then open /mcp to approve any sign-in the server asks for.
Claude Desktop
https://mcp.pricewatcha.comAdd a custom connector in Settings, paste this address, and approve the sign-in.
Cursor
cursor://anysphere.cursor-deeplink/mcp/install?name=pricewatcha-api&config=eyJ1cmwiOiJodHRwczovL21jcC5wcmljZXdhdGNoYS5jb20ifQ==Open the link and Cursor adds the server at that address.
ChatGPT
https://mcp.pricewatcha.comIn Settings, enable Developer mode, create an MCP app, and paste this address. Your plan and workspace must allow custom apps.
Codex
codex mcp add pricewatcha-api --url 'https://mcp.pricewatcha.com'Run it once, then sign in with codex mcp login pricewatcha-api if the server asks for an account.
From the project's README
As published by pricewatcha/pricewatcha-api in README.md.
The Pricewatcha API is the Structured Product Price Intelligence Platform for developers, automation and AI Agents.
The Pricewatcha API derives from the pricewatcha.com application. It provides price tracking, alerts and product intelligence beyond the Pricewatcha dashboard. This repository documents the public HTTP API, OpenAPI schema, official SDKs, MCP server and examples. It does not contain the production web application or scrapers.
Status: Available · Version: v1 · Base URL: https://pricewatcha.com/api/v1
Interactive API keys (browser): Profile & API Keys
Optional: verify connectivity with GET https://pricewatcha.com/api/v1/health. Then pick one of the three paths below.
Quickstart
Path 1: Browse prices (no auth)
Use demo product IDs from the demo catalog or search the catalog:
curl -s "https://pricewatcha.com/api/v1/products/demo_iphone_15_pro"
curl -s "https://pricewatcha.com/api/v1/search?q=iphone+15&limit=10"
Search is case-insensitive token AND (all terms must appear; word order does not matter). Results include the full Pricewatcha catalog, not only URLs submitted via POST /track. Use product_id from search for product and price-history endpoints (prod_* or demo_*).
Path 2: Track a product and get price history
curl -s -X POST "https://pricewatcha.com/api/v1/track" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.backmarket.de/de-de/p/example-product"}'
curl -s "https://pricewatcha.com/api/v1/products/{productId}/price-history"
POST /track returns HTTP 200 with a bounded server-side long-poll (~25s). Use product_id from the response for price history. Optional: send Authorization: Bearer pwk_live_… for higher track, search and product-read quotas.
Fast shops return status: "completed" with the full product in one call. Slow shops return status: "running" with a job_id. Poll GET https://pricewatcha.com/api/v1/jobs/{jobId} until the job is completed or failed. More detail: Async track & poll.
Path 3: Price alert with webhook (API key required)
Create a key in Profile & API Keys, then:
curl -s -X POST "https://pricewatcha.com/api/v1/alerts" \
-H "Authorization: Bearer pwk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_a1b2c3d4e5",
"notify_on_drop": true,
"min_threshold_price": 500.00,
"webhook_url": "https://your-n8n-instance.com/webhook/abc",
"notify_email": true
}'
For authentication and data boundaries, see Authentication and Data boundaries.
Authentication
No credential required for catalog search, product detail, price history and async track/poll. Without a key those endpoints use anonymous rate limits. Send an API key to use the higher per-account track, search and product-read quotas.
Protected API v1 endpoints (alerts, webhooks, authenticated track callbacks) use:
Authorization: Bearer pwk_live_…
| Credential | Format | When to use |
|---|---|---|
| API key | pwk_live_… | Recommended for scripts, agents, n8n and server integrations. Create in Profile & API Keys. |
| Login session token | JWT from POST https://pricewatcha.com/api/auth/login | Website UI and headless key bootstrap only |
Do not use the login session token for alerts, webhooks or other API v1 calls once you have an API key.
See Access model for which routes are public vs authenticated.
API keys (browser)
Log in and open Profile & API Keys to create and manage API keys in your browser. The full secret is shown once at creation.
For agents without a browser, use headless key bootstrap below.
Using your key on protected endpoints:
curl -s -X POST "https://pricewatcha.com/api/v1/alerts" \
-H "Authorization: Bearer pwk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"product_id": "prod_a1b2c3d4e5", "notify_on_drop": true}'
Headless key bootstrap (for agents)
If an agent must obtain API credentials without a browser, authenticate once with the same email and password as on the website, create an API key, then use pwk_live_… for all further calls. This is not a separate agent login: it is the normal Pricewatcha account login exposed as an HTTP endpoint.
How login via API works
POST https://pricewatcha.com/api/auth/login accepts JSON email and password and returns a short-lived access_token (login session token). The Developer page login modal calls the same endpoint; in a script or agent you call it directly with curl or your HTTP client.
- You need an existing account (register on the site or via
POST https://pricewatcha.com/api/auth/register). - The email must be verified: otherwise the API returns 403.
- Wrong credentials return 401.
- Use
access_tokenonly to create keys; for alerts and webhooks use thepwk_live_…key from step 2.
Step 1: Login
curl -s -X POST "https://pricewatcha.com/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "YOUR_PASSWORD"}'
Response (HTTP 200), AuthResponse:
access_token(string): login session token (JWT)token_type(string): always"bearer"user(object):id(string, UUID),email(string),email_verified(boolean)
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "you@example.com",
"email_verified": true
}
}
Send the token as Authorization: Bearer <access_token> in step 2. Session tokens expire; do not store them as the long-term credential for an agent.
Step 2: Create API key
curl -s -X POST "https://pricewatcha.com/api/keys" \
-H "Authorization: Bearer ACCESS_TOKEN_FROM_STEP_1" \
-H "Content-Type: application/json" \
-d '{"name": "agent bootstrap"}'
Response (HTTP 200), CreateApiKeyResponse:
id(integer): key IDname(string): label from the requestkey_prefix(string): first 12 characters of the key (for display)key(string): full secret; returned only on create, not on listis_active(boolean)created_at(string, ISO 8601 datetime)last_used_at(string ornull)revoked_at(string ornull)
{
"id": 42,
"name": "agent bootstrap",
"key_prefix": "pwk_live_ab",
"key": "pwk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"is_active": true,
"created_at": "2026-05-27T14:30:00.123456",
"last_used_at": null,
"revoked_at": null
}
Store key securely. Use it on alerts, webhooks and other protected API v1 endpoints, not the session token from step 1.
API endpoints (overview)
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /api/v1/health | - | Health check |
GET | /api/v1 | - | Discovery and disclaimer |
POST | /api/v1/track | - | URL ingestion (long-poll) |
GET | /api/v1/jobs/{jobId} | - | Job status |
GET | /api/v1/products/{productId} | - | Product intelligence |
GET | /api/v1/products/{productId}/price-history | - | History and trend |
GET | /api/v1/search?q= | - | Keyword search (limit max 200) |
GET | /api/v1/openapi.json | - | Live OpenAPI 3.1 |
POST | /api/auth/login | - | Login (short-lived session token) |
POST | /api/keys | Session token | Create API key |
GET / DELETE | /api/keys … | Session token or key | List / revoke keys |
* | /api/v1/alerts … | API key | Price alerts |
* | /api/v1/watchlist / …/watch | API key | Continuous price watchlist |
* | /api/v1/webhooks … | API key | Webhook subscriptions |
Machine-readable contract: openapi/openapi.yaml · Live: GET https://pricewatcha.com/api/v1/openapi.json
Rate limits
Current limits (indicative)
The following limits apply and may change without notice.
| Class | Endpoint | Anonymous | Authenticated (API key) |
|---|---|---|---|
| Track (concurrent) | POST /track | ~2 in-flight jobs | ~4 in-flight jobs |
| Track (burst) | POST /track | ~10 jobs / 60s | ~20 jobs / 60s |
| Track (hourly) | POST /track | ~40 jobs / hour | ~120 jobs / hour |
| Track (daily) | POST /track | ~80 jobs / day | ~400 jobs / day |
| Job poll | GET /jobs/{id} | ~40 req/min per client | same |
| Search (burst) | GET /search | ~20 req / 60s | ~40 req / 60s |
| Search (hourly) | GET /search | ~60 req / hour | ~180 req / hour |
| Search (daily) | GET /search | ~200 req / day | ~1000 req / day |
| Read (burst) | /products, /price-history | ~60–120 req/min per client | ~240 req / 60s |
| Read (hourly) | /products, /price-history | ~180 req / hour | ~540 req / hour |
| Read (daily) | /products, /price-history | ~600 req / day | ~3000 req / day |
| Health | /health and / | Unlimited | Unlimited |
Send Authorization: Bearer pwk_live_… on POST /track, GET /search, or product reads to use the authenticated tier. Those endpoints remain available without a key at the anonymous limits.
Client identity: anonymous limits are keyed by client IP. Behind Cloudflare the API prefers
CF-Connecting-IPoverX-Forwarded-Forso edge proxy IPs are not treated as distinct clients. The hosted MCP server forwards a stableX-Pricewatcha-Client-Id(OAuth token hash, else connecting-IP hash) with a shared proxy secret so MCP callers are not all bucketed under one egress IP. Authenticated track, search and product-read quotas are keyed by account (owner_id), not IP.
Monitor
X-RateLimit-Remainingand honor429with exponential backoff.X-RateLimit-Policynames which window the headers refer to (track,track_hourly,track_daily,track_concurrent,job_read,search,search_hourly,search_daily,read,read_hourly, orread_daily).
Track quotas are counted from persisted jobs (api_track_jobs by client key or account), so they apply across multiple app instances. A long-poll that holds the HTTP connection for ~25s still counts as one track job when created — sequential tracks spaced farther apart than 60s will not trip the burst window, but hourly/daily and concurrent caps still apply.
Agents should prefer: start track → poll GET /jobs/{id} with backoff (not every 1–2s) → read product/history once complete. Retrying POST /track with the same URL while that job is still queued/processing reuses the existing job and does not consume another concurrent slot. Jobs left queued/processing longer than the scrape timeout (default 600s) are failed so slots cannot leak across deploys.
Search and product-read quotas are in-memory per app instance (not shared across Railway replicas the way track jobs are). Authenticated callers still get the higher per-account windows. Polling the same catalog queries on a short interval will still trip the hourly/daily search windows.
Exact numbers may change without notice (env overrides: API_V1_TRACK_*, API_V1_TRACK_AUTH_*, API_V1_JOB_READ_*, API_V1_READ_*, API_V1_READ_AUTH_*, API_V1_SEARCH_*, API_V1_SEARCH_AUTH_*).
Headers
When rate limiting is active, responses may include:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests in the window |
X-RateLimit-Remaining | Requests left in the window |
X-RateLimit-Reset | Unix timestamp when the window resets |
X-RateLimit-Policy | Which window the headers describe |
HTTP 429
When limited, the API returns 429 Too Many Requests with a JSON body:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded (track daily). Try again later.",
"http_status": 429,
"retry_recommended": true,
"retry_after_seconds": 3600
}
}
Agent guidance: honor 429, wait until retry_after_seconds / X-RateLimit-Reset, and reduce poll frequency on job status endpoints. Prefer spreading tracks over time rather than bursting near the hourly/daily caps. Anonymous 429 responses mention that an API key raises quotas.
Operators can receive an email when hourly/daily/concurrent track limits or hourly/daily search and product-read limits trip (cooldown per client; see API_V1_RATE_LIMIT_ALERT_*).
Abuse and IP restrictions
Sustained abuse of anonymous daily quotas (track, search, or product reads — for example exhausting the daily limit on several days from the same IP) may trigger an in-app restriction, not only 429.
- Notice (grace period). API calls still succeed. Responses include
X-Pricewatcha-Restriction: noticeandX-Pricewatcha-Restriction-Messagewith the pending-block warning. Rate limits still apply. - Block. If there is no reply, the IP is blocked. Further calls return HTTP
403witherror.codeaccess_restricted.
Email info@pricewatcha.com to discuss terms or restore access. Do not retry until access is restored. Retries will not lift the restriction.
Async track and poll
POST /api/v1/track submits a product URL and waits up to ~25 seconds (long-poll). No API key is required. Send Authorization: Bearer pwk_live_… to use higher per-account track quotas.
- Fast shops:
status: "completed"with fullproductin the same response - Slow shops:
status: "running"+job_id: pollGET /api/v1/jobs/{jobId}untilcompletedorfailed - Repeat
POST /trackfor the same URL while a job is in flight returns that job instead of starting another (and instead of a concurrent 429) - With an API key:
watch: trueenrolls the product for continuous scheduler updates;refresh: trueforces a re-scrape even if the URL is already in the catalog
Jobs are retained for 72 hours. After expiry, GET /jobs/{jobId} returns 404: use GET /products/{productId} instead.
Typical flows
Fast shop (one call)
POST /api/v1/track → { "status": "completed", "product": { ... } }
Slow shop
POST /api/v1/track → { "status": "running", "job_id": "job_xxx", "hint": "..." }
GET /api/v1/jobs/{jobId} → poll until terminal state
GET /api/v1/products/{productId} and .../price-history
Track a product
curl -s -X POST "https://pricewatcha.com/api/v1/track" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.backmarket.de/de-de/p/example-product"}'
Response (200) when the scrape completes within the long-poll window:
{
"job_id": "job_xxxxxxxx",
"status": "completed",
"product": {
"product_id": "prod_xxxxxxxx",
"name": "Example product",
"shop": "Back Market",
"current_price": 563,
"currency": "EUR"
},
"error": null
}
Response (200) when still running after the long-poll timeout:
{
"job_id": "job_xxxxxxxx",
"status": "running",
"product": null,
"error": null,
"hint": "Job still running. Call the get_job_status tool with this job_id to poll for the result."
}
Poll job status
curl -s "https://pricewatcha.com/api/v1/jobs/job_xxxxxxxx"
Completed response
{
"job_id": "job_xxxxxxxx",
"status": "completed",
"product": {
"product_id": "prod_xxxxxxxx",
"name": "Example product",
"shop": "Back Market",
"current_price": 563,
"currency": "EUR"
}
}
Job states
| Status | Meaning |
|---|---|
queued | Job accepted, waiting to start |
running | Ingestion in progress |
completed | Product intelligence in product |
failed | Scrape failed: read structured error (HTTP 200 job lookup) |
Recommended client flow
POST /trackwith{ "url": "..." }→ 200- If
runningorqueued, pollGET /jobs/{jobId}every 2–5 seconds - On
completed, readproductfrom the job orGET /products/{productId} - On
failed, surfaceerror.code; backoff before retrying
Job lookup vs. scrape failure
When polling GET /jobs/{jobId}, interpret HTTP status and body together:
| Response | Meaning | What to do |
|---|---|---|
| HTTP 404 | No job with this job_id (wrong ID or job expired after 72h) | Stop polling; start a new POST /track if you still need the product |
HTTP 200 with "status": "failed" | Job exists, but scraping failed | Read error.code in the JSON body (e.g. scrape_target_not_found) |
A 404 is a lookup problem. A 200 with failed is a completed job whose scrape did not succeed.
Track job webhooks (push)
Authenticated clients can receive a push when a track job finishes: use callback_url (one-off) or webhook_id (existing subscription). Mutually exclusive. Callbacks do not consume extra quota beyond the authenticated track job.
curl -s -X POST "https://pricewatcha.com/api/v1/track" \
-H "Authorization: Bearer pwk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.backmarket.de/de-de/p/example-product",
"callback_url": "https://n8n.example.com/webhook/track-done"
}'
With callback_url, the track response may include callback_secret (whsec_…) once: same signing as subscription webhooks.
When the job finishes, Pricewatcha sends a webhook with event type track_job_completed or track_job_failed (same payload shape as other webhooks). If you do not use push delivery, you can still wait on POST /track (long-poll) or poll GET /jobs/{jobId} until the job reaches a terminal state.
Note: Anonymous
POST /trackwithcallback_urlorwebhook_idreturns400 auth_required_for_callback. MCP tools use track → poll (nocallback_urlin v1).
SDK convenience
Official Python and TypeScript SDKs may provide track_and_wait() / trackAndWait(): a helper that calls POST /track, then polls GET /jobs/{jobId} until the job is completed or failed and returns the result. The HTTP API stays async-first; the helper only saves you from writing the poll loop yourself. See SDKs.
Deduplication
Repeated POST /track for the same URL may return completed quickly with existing intelligence.
Timeouts
Long-poll default is ~25 seconds. For slow shops, poll GET /jobs/{jobId} instead of extending the track timeout.
Search
Keyword search is case-insensitive. The query is split into tokens; a product matches when every token appears in the normalized product name, URL, platform/shop or related fields. Word order does not matter, and punctuation such as hyphens and slashes is treated as whitespace (Darth-Vader matches Darth Vader). Results cover the full Pricewatcha catalog, not only URLs submitted via POST /track.
Exact contiguous phrases still rank above other token matches when both match.
Endpoint
GET https://pricewatcha.com/api/v1/search?q=…&limit=…
Optional limit: default 50, maximum 200. Applied after exclude-term filtering.
Search is rate-limited separately from product reads. Anonymous callers get ~20 requests / 60s, ~60 / hour, ~200 / day; an API key raises that to ~40 / 60s, ~180 / hour, ~1000 / day per account. Honor HTTP 429 and X-RateLimit-Policy; see Rate limits.
q supports Google-style minus-prefixed exclude terms. q=iPhone+15+-cover+-case returns products matching both "iPhone" and "15" that do not contain "cover" or "case" in the searchable fields (case-insensitive). A lone - is ignored.
curl -s "https://pricewatcha.com/api/v1/search?q=iphone&limit=10"
curl -s "https://pricewatcha.com/api/v1/search?q=iPhone+15+-cover+-case"
curl -s "https://pricewatcha.com/api/v1/search?q=Darth+Vader+DX27"
Example response
[
{
"product_id": "demo_iphone_15_pro",
"name": "Apple iPhone 15 Pro 128GB (Refurbished)",
"shop": "Back Market",
"product_url": "https://www.backmarket.de/de-de/p/example-iphone-15-pro",
"current_price": 563,
"currency": "EUR",
"status": "active",
"preview": true,
"google_product_category_id": null,
"google_product_category_name": null
},
{
"product_id": "prod_a1b2c3d4e5",
"name": "iPhone 15 Pro",
"shop": "Swappie",
"product_url": "https://swappie.com/de/p/iphone-15-pro/",
"current_price": 505,
"currency": "EUR",
"status": "active",
"google_product_category_id": null,
"google_product_category_name": null
}
]
Use product_url for direct linking without an extra GET /products/{id} call.
Results always include google_product_category_id and google_product_category_name (null when unset). You do not need an extra query parameter.
Demo catalog (no scrape required)
Preview demo products are always available for integration testing:
curl -s "https://pricewatcha.com/api/v1/products/demo_iphone_15_pro"
curl -s "https://pricewatcha.com/api/v1/products/demo_iphone_15_pro/price-history"
curl -s "https://pricewatcha.com/api/v1/search?q=iphone+15+pro"
See the demo catalog on GitHub.
Data boundaries
Catalog price intelligence (current price, history, product metadata) is available without authentication. User-specific data (accounts, emails, alert settings) is never exposed on public read endpoints.
Authenticated clients can manage their own watchlist via /api/v1/watchlist and /api/v1/products/{id}/watch (API key required). Other users' watchlists are never returned.
Readable fields
product_id, name, shop/platform, product URL- Current price, currency, last checked, status
- Price history, historical low/high, average, trend
data_sourceanddata_source_labelwhen price data comes directly from a merchant feed (merchant_feed→"Direct merchant data")google_product_category_idandgoogle_product_category_nameon product detail and search (null when unset). Search does not require an extra query parameter.- Demo entries may include
"preview": true
Search, product detail and price history return the same fields whether the product was added via dashboard, API, MCP or demo data.
Continuous updates
Only products on an account watchlist (dashboard or API watch / alert / product-scoped price webhook) are refreshed by the price scheduler. One-shot POST /track without watch does not enroll the product for ongoing updates.
Product IDs
| Prefix | Meaning |
|---|---|
demo_* | Static preview samples (e.g. demo_iphone_15_pro) |
prod_* | Opaque stable ID per catalog product (one per URL entity) |
Use product_id from search or a completed track job for GET /products/{productId} and .../price-history.
Webhook payloads
Deliveries include product-level event data only (prices, product IDs, event type), not user emails or account details. Verify authenticity with the subscription signing secret (whsec_...); see Webhooks.
Compliance
If you build on this API, disclose to your users that prices are informational and that merchant sites are authoritative.
Errors and error codes
Non-success responses use a structured error object. Inspect error.code: do not parse free-text message values.
Shape
Shortened here. Read the whole README on GitHub.
Tools it offers (15)
What this server listed when Ahel dialed its public endpoint in Oct 2026, with no key and no account of yours. The names are the server’s own.
get_api_statustrack_productget_job_statusget_productget_price_historysearch_productscreate_price_alertlist_price_alertsget_price_alertupdate_price_alertdelete_price_alertwatch_productunwatch_productlist_watchlistget_watch_status
Signals
- GitHub stars
- 1
- Last commit
- Oct 2026
Advanced
- Delivery
- pricewatcha MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
- Item type
- mcp-server
- Key
io-github-pricewatcha-pricewatcha- Source
- github.com/pricewatcha/pricewatcha-api
- Hosted endpoint
https://mcp.pricewatcha.com
github.com/pricewatcha/pricewatcha-api
More in Monitoring & ops
MCP server
More in Monitoring & opsWorld Monitor
MCP server · koala73
More in Monitoring & opsNetdata
MCP server · netdata
More in Monitoring & opsotakit
MCP server · otakit
More in Monitoring & opsStatuser
MCP server · statuser-cloud
More in Monitoring & opsaltmetric-mcp
MCP server · altmetric
More in Monitoring & ops