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: Public preview · Version: v1 (first release) · Base URL: https://pricewatcha.com/api/v1
Interactive API keys (browser): Developer page
Optional: verify connectivity with GET https://pricewatcha.com/api/v1/health. Then pick one of the three paths below.
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 matches product name, URL and platform/shop (case-insensitive). 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_*).
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.
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.
Create a key on the Developer page, 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",
"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.
No credential required for catalog search, product detail, price history and async track/poll.
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 on the Developer page. |
| 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.
Log in on the Developer page 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", "min_threshold_price": 499.00}'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.
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.
| 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/webhooks … |
API key | Webhook subscriptions |
Machine-readable contract: openapi/openapi.yaml · Live: GET https://pricewatcha.com/api/v1/openapi.json
The following limits apply during public preview and may change without notice.
| Class | Endpoint | Approx. limit |
|---|---|---|
| Track | POST /track |
~10 req/min per IP |
| Read | /search, /products, /price-history, /jobs |
~60 req/min per IP |
| Health | /health and / |
Unlimited |
Monitor
X-RateLimit-Remainingand honor429with exponential backoff.
Limits group into Track (POST /track, stricter, to limit ingestion abuse) and Read (all other /api/v1/*, higher, for caching-friendly reads). Exact numbers may change during preview.
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 |
When limited, the API returns 429 Too Many Requests with a JSON body:
{ "detail": "Rate limit exceeded. Try again later." }Agent guidance: honor 429, wait until X-RateLimit-Reset and reduce poll frequency on job status endpoints.
POST /api/v1/track submits a product URL and waits up to ~25 seconds (long-poll).
- Fast shops:
status: "completed"with fullproductin the same response - Slow shops:
status: "running"+job_id: pollGET /api/v1/jobs/{jobId}untilcompletedorfailed
Jobs are retained for 72 hours. After expiry, GET /jobs/{jobId} returns 404: use GET /products/{productId} instead.
POST /api/v1/track → { "status": "completed", "product": { ... } }
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
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."
}curl -s "https://pricewatcha.com/api/v1/jobs/job_xxxxxxxx"{
"job_id": "job_xxxxxxxx",
"status": "completed",
"product": {
"product_id": "prod_xxxxxxxx",
"name": "Example product",
"shop": "Back Market",
"current_price": 563,
"currency": "EUR"
}
}| 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) |
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
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.
Authenticated clients can receive a push when a track job finishes: use callback_url (one-off) or webhook_id (existing subscription). Mutually exclusive. Same rate limits as anonymous POST /track.
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).
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.
Repeated POST /track for the same URL may return completed quickly with existing intelligence.
Long-poll default is ~25 seconds. For slow shops, poll GET /jobs/{jobId} instead of extending the track timeout.
Keyword search is case-insensitive and matches product name, URL, platform/shop and related fields. Results cover the full Pricewatcha catalog, not only URLs submitted via POST /track.
GET https://pricewatcha.com/api/v1/search?q=…&limit=…
Optional limit: default 50, maximum 200.
curl -s "https://pricewatcha.com/api/v1/search?q=iphone&limit=10"[
{
"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
},
{
"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"
}
]Use product_url for direct linking without an extra GET /products/{id} call.
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.
Catalog price intelligence (current price, history, product metadata) is available without authentication. User-specific data (accounts, emails, alert settings, private watchlists) is never exposed through the public API.
product_id, name, shop/platform, product URL- Current price, currency, last checked, status
- Price history, historical low/high, average, trend
- 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.
| 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.
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.
If you build on this API, disclose to your users that prices are informational and that merchant sites are authoritative.
Non-success responses use a structured error object. Inspect error.code: do not parse free-text message values.
{
"error": {
"code": "invalid_url_type",
"message": "url looks like a search or listing page (query parameter 'k')",
"http_status": 400,
"retry_recommended": false,
"retry_after_seconds": null
}
}| Field | Description |
|---|---|
code |
Stable machine identifier |
message |
Human-readable detail (not for branching logic) |
http_status |
HTTP status echoed in the body |
retry_recommended |
Whether a retry may help |
retry_after_seconds |
Hint when rate-limited (may be null) |
| Code | Typical HTTP | When |
|---|---|---|
invalid_input_format |
400 | Malformed JSON or parameters |
invalid_url_type |
400 | URL is a search/listing page, unsupported shop, etc. |
job_not_found |
404 | Unknown or expired job_id (jobs expire after 72h) |
product_not_found |
404 | Unknown product_id |
scrape_target_not_found |
404 | Product page not found on the shop |
scrape_chain_exhausted |
502 | All scraper strategies failed |
rate_limited |
429 | Per-IP limit exceeded: honor retry_after_seconds |
internal_error |
500 | Unexpected server error |
| Code | Typical HTTP | When |
|---|---|---|
unauthenticated |
401 | Missing or invalid bearer token |
invalid_session_token |
401 | Expired or invalid login session (not an API key) |
invalid_api_key |
401 | Revoked or unknown API key |
api_key_limit_reached |
403 | Account key quota exceeded |
api_key_not_found |
404 | Key id not found |
| Code | Typical HTTP | When |
|---|---|---|
alert_already_exists |
409 | One alert per user per product: use PATCH |
alert_not_found |
404 | Unknown alert_id |
webhook_not_found |
404 | Unknown subscription |
webhook_limit_reached |
403 | Subscription quota exceeded |
auth_required_for_callback |
400 | callback_url / webhook_id on POST /track without auth |
callback_conflict |
400 | Both callback_url and webhook_id set |
invalid_callback_url |
400 | Callback URL not HTTPS or blocked target |
- Branch on
error.code, notmessage. - When
retry_recommendedistrue, use exponential backoff and respectretry_after_seconds. - HTTP 200 on
GET /jobs/{jobId}withstatus: "failed"is a job failure, not a transport error.
Full schemas: live GET https://pricewatcha.com/api/v1/openapi.json and the OpenAPI spec on GitHub.
Create price alerts that send email notifications and/or fire webhooks when a threshold is crossed.
Each tracked product has one alert record per user with optional:
min_threshold_price: notify when price drops to or belowmax_threshold_price: notify when price rises to or above
At least one threshold is required.
All endpoints require an API key in Authorization: Bearer …. Full schemas: GET https://pricewatcha.com/api/v1/openapi.json (tag alerts).
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/alerts |
List your alerts. Optional: ?product_id=prod_… |
POST |
/api/v1/alerts |
Create alert. 409 alert_already_exists if one exists: use PATCH |
GET |
/api/v1/alerts/{alertId} |
Get one alert |
PATCH |
/api/v1/alerts/{alertId} |
Update thresholds, webhook URL, email, name, is_active |
DELETE |
/api/v1/alerts/{alertId} |
Delete (204) |
curl -s -X POST "https://pricewatcha.com/api/v1/alerts" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_a1b2c3d4e5",
"min_threshold_price": 499.00,
"max_threshold_price": 599.00,
"webhook_url": "https://n8n.example.com/webhook/alert",
"notify_email": true,
"name": "Deal range"
}'Example response (201):
{
"alert_id": 76,
"product_id": "prod_a1b2c3d4e5",
"min_threshold_price": 499.00,
"max_threshold_price": 599.00,
"currency": "EUR",
"webhook_url": "https://n8n.example.com/webhook/alert",
"notify_email": true,
"name": "Deal range",
"is_active": true,
"created_at": "2026-05-24T12:00:00Z",
"updated_at": "2026-05-24T12:00:00Z",
"last_triggered_at": null
}curl -s "https://pricewatcha.com/api/v1/alerts" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"
curl -s "https://pricewatcha.com/api/v1/alerts?product_id=prod_a1b2c3d4e5" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"
curl -s "https://pricewatcha.com/api/v1/alerts/76" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"curl -s -X PATCH "https://pricewatcha.com/api/v1/alerts/76" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"min_threshold_price": 479.00, "notify_email": false}'
curl -s -X PATCH "https://pricewatcha.com/api/v1/alerts/76" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"is_active": false}'
curl -s -X DELETE "https://pricewatcha.com/api/v1/alerts/76" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"Webhooks push signed HTTP POST requests when prices change, alert thresholds are crossed or authenticated track jobs complete.
Subscribe to event types globally or for a single product_id. Each event type is delivered as its own request.
Manage subscriptions via POST https://pricewatcha.com/api/v1/webhooks. Full schemas: GET https://pricewatcha.com/api/v1/openapi.json (tags webhooks, alerts).
Note: Target URLs must use HTTPS and must not resolve to private or internal IP ranges.
| Event type | Trigger |
|---|---|
price_changed |
Price moved by more than €0.01 |
price_dropped |
Price decreased by more than €0.01 |
price_increased |
Price increased by more than €0.01 |
new_historical_low |
New price strictly lower than any previous observation |
price_alert_triggered |
User alert threshold crossed (min and/or max) |
track_job_completed |
Authenticated POST /track finished successfully |
track_job_failed |
Authenticated POST /track failed |
webhook_test |
Only from POST /api/v1/webhooks/{webhook_id}/test |
{
"event_id": "evt_a1b2c3d4e5",
"event_type": "price_dropped",
"occurred_at": "2026-05-24T14:00:00Z",
"product": {
"product_id": "prod_a1b2c3d4e5",
"name": "Apple iPhone 15 Pro 128GB (Refurbished)",
"shop": "Back Market",
"product_url": "https://www.backmarket.de/...",
"currency": "EUR"
},
"price": {
"old_price": 599.00,
"new_price": 536.00,
"historical_low": 536.00,
"historical_high": 729.00,
"average_price": 612.50
},
"metadata": {
"source": "pricewatcha",
"api_version": "v1"
}
}Includes the same product and price blocks plus an alert object:
{
"event_id": "evt_b2c3d4e5f6",
"event_type": "price_alert_triggered",
"occurred_at": "2026-05-24T14:00:00Z",
"alert": {
"alert_id": "76",
"min_threshold_price": 549.00,
"max_threshold_price": 599.00,
"threshold_reached": "min",
"name": "Under €550"
},
"metadata": {
"source": "pricewatcha",
"api_version": "v1"
}
}Every delivery includes:
X-Pricewatcha-Event-IdX-Pricewatcha-Event-TypeX-Pricewatcha-Timestamp(Unix seconds)X-Pricewatcha-Signature(sha256=<hex>)
Signed string: "{timestamp}.{raw_body}" with HMAC-SHA256 and your webhook secret (whsec_…, shown once at subscription creation).
Warning: The webhook secret is shown only once. Store it securely: only
secret_prefixis shown afterward.
import hmac
import hashlib
def verify_pricewatcha_webhook(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
f"{timestamp}.{raw_body.decode('utf-8')}".encode("utf-8"),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature or "")import crypto from "node:crypto";
function verifyPricewatchaWebhook(secret, timestamp, rawBody, signature) {
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const expectedHeader = `sha256=${expected}`;
return crypto.timingSafeEqual(
Buffer.from(expectedHeader),
Buffer.from(signature || "")
);
}Failed deliveries retry up to 5 times: 1 min → 5 min → 30 min → 2 h → 12 h.
After 10 consecutive failures the subscription is auto-disabled.
curl -s "https://pricewatcha.com/api/v1/webhooks/{webhook_id}/deliveries" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"curl -s -X POST "https://pricewatcha.com/api/v1/webhooks" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"target_url": "https://n8n.example.com/webhook/abc123",
"event_types": ["price_dropped", "new_historical_low"],
"product_id": "prod_a1b2c3d4e5"
}'curl -s -X POST "https://pricewatcha.com/api/v1/webhooks/42/test" \
-H "Authorization: Bearer pwk_live_YOUR_KEY_HERE"Pricewatcha exposes a remote MCP endpoint: no local installation required. Connect your AI client with the URL below. Available tools include get_api_status, search_products, track_product, get_job_status, get_product and get_price_history.
https://mcp.pricewatcha.com
For step-by-step setup, see Claude, ChatGPT, n8n and Make below.
What it enables: Ask Claude to search for products, track prices, check price history, set alerts and manage webhooks, all in natural language, directly in Claude.ai or the Claude desktop app.
Step 1: Open the Customize panel
Click Customize (sliders icon) in the left sidebar of Claude.ai or go to claude.ai/settings/connectors.
Step 2: Add a custom connector
Under Connectors, click + to add a new connector.
Step 3: Enter the MCP server URL
Enter a name (e.g. “Pricewatcha”) and paste:
https://mcp.pricewatcha.com
Click Add.
Step 4: Done
Pricewatcha appears in your connector list with read-only tools (get_api_status, get_job_status, get_product, get_price_history, search_products) and write tools (track_product). You can now use Pricewatcha in any Claude conversation.
Step 5: Configure tool permissions (optional)
Open the connector in your connector list (or return to claude.ai/settings/connectors) and expand Tool permissions.
For each tool — or for the whole Read-only / Write group — choose when Claude may call it:
| Setting | Meaning |
|---|---|
| Always allow | Claude calls the tool without asking each time |
| Require approval | Claude asks before each call (default for new connectors) |
| Never allow | Tool is blocked |
For everyday price checks and searches, set the read-only tools (or the whole read-only group) to Always allow. For track_product, pick Always allow if you want friction-free tracking, or keep Require approval if you prefer to confirm before a product is tracked.
Same steps: Customize → Connectors → Add custom connector → paste https://mcp.pricewatcha.com. Tool permissions are configured the same way under Tool permissions in the connector settings.
Try:
- “Find me a refurbished iPhone 15 Pro under €550”
- “Track this product URL and show me the price history”
- “Set an alert for this product when it drops below €500”
Note:
track_productis a write tool because it creates a tracking job in the background. It does not modify or delete existing data.
What it enables: Search products, track prices, get price history, set price alerts and manage webhooks, directly in ChatGPT via MCP.
Prerequisite: Developer Mode (one-time)
Custom MCP connectors require Developer Mode: Settings → Advanced → enable Developer Mode. Available on Plus, Pro, Team, Business, Enterprise and Edu (not on the free plan). Pricewatcha tools only work while Developer Mode stays on.
Step 1: Go to Settings → Apps and click Add custom connector.
Step 2: Paste the MCP URL:
https://mcp.pricewatcha.com
Optional connector logo: PNG, max 10 KB. Download from https://pricewatcha.com/static/img/mcp/chatgpt-logo.png
Step 3: Authentication: Select OAuth. ChatGPT handles the flow; you may see a brief authorization prompt on first connect.
Step 4: Done. Example prompts:
- “Search for a refurbished iPhone 15 Pro under €550”
- “Track this product URL and show me the price history”
Warning: ChatGPT may show a DEV label on unverified third-party connectors. Pricewatcha only works while Developer Mode is enabled.
What it enables: Build automated price-monitoring workflows. Trigger actions when prices change or cross your alert threshold: no coding required.
Typical use case: When a tracked product drops below your threshold → send a Telegram, Slack or email notification with product name, shop, current price and alert name.
Note: A publicly accessible URL is only required if you run n8n locally (self-hosted on your own machine). If you use n8n Cloud or a server-hosted instance, your n8n webhook URL is already publicly accessible: skip the tunnel step.
- Create a Webhook node in n8n → copy the Production URL.
- Create a Pricewatcha alert with
webhook_urlset to the n8n URL (see below). - Done:
price_alert_triggeredevents are delivered when thresholds are crossed.
- Start a Cloudflare Tunnel:
cloudflared tunnel --url http://localhost:5678(install withbrew install cloudflaredon macOS). - Copy the tunnel URL (e.g.
https://abc123.trycloudflare.com). - Create a Webhook node in n8n → note the path (e.g.
/webhook-test/abc123). - Combine:
https://abc123.trycloudflare.com/webhook-test/abc123. - Use this as
webhook_urlin the Pricewatcha alert.
Requires an API key:
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_YOUR_PRODUCT_ID",
"min_threshold_price": 600.00,
"webhook_url": "https://YOUR_N8N_URL/webhook/YOUR_PATH",
"notify_email": false,
"name": "Price drop alert"
}'When the current price is at or below min_threshold_price, Pricewatcha sends a price_alert_triggered event with this payload shape:
{
"event_id": "evt_...",
"event_type": "price_alert_triggered",
"occurred_at": "2026-05-26T20:32:07Z",
"product": {
"product_id": "prod_...",
"name": "iPhone 15 Pro",
"shop": "Swappie",
"current_price": 559.00,
"currency": "EUR"
},
"price": {
"old_price": 559.00,
"new_price": 559.00,
"historical_low": 7.99,
"historical_high": 649.00,
"average_price": 570.44
},
"alert": {
"alert_id": "77",
"min_threshold_price": 600.00,
"threshold_reached": "min",
"name": "Price drop alert"
},
"metadata": {
"source": "pricewatcha",
"api_version": "v1"
}
}- Webhook node (trigger): receives the
price_alert_triggeredevent. - IF node: filter:
{{ $json.body.event_type }}equalsprice_alert_triggered. - Notification node: Email / Telegram / Slack with:
- Product:
{{ $json.body.product.name }} - Shop:
{{ $json.body.product.shop }} - Current price:
{{ $json.body.price.new_price }} {{ $json.body.product.currency }} - Alert name:
{{ $json.body.alert.name }}
- Product:
curl -s -X POST "https://pricewatcha.com/api/v1/webhooks/YOUR_WEBHOOK_ID/test" \
-H "Authorization: Bearer pwk_live_YOUR_KEY"Note: The test endpoint requires a webhook subscription (
POST https://pricewatcha.com/api/v1/webhooks), not an alert.
Signature verification: Verify
X-Pricewatcha-Signature(HMAC-SHA256) in production: see Webhook signing.
Alternative: use the HTTP Request node: GET https://pricewatcha.com/api/v1/search?q=… or GET https://pricewatcha.com/api/v1/products/PRODUCT_ID/price-history.
What it enables: Same webhook-based automation as n8n: visual workflows without code.
| n8n | Make equivalent |
|---|---|
| Webhook Trigger | Webhooks → Custom webhook |
| IF node | Router or Filter |
| HTTP Request | HTTP → Make a request |
| Notification nodes | Email / Telegram / Slack |
- Create a scenario with Custom webhook as trigger; copy the URL.
- Create a Pricewatcha webhook subscription (same
curlas the n8n guide, use your Make URL astarget_url). - Add a Router on
event_type. - Test with
POST https://pricewatcha.com/api/v1/webhooks/{id}/test.
Make free plan: Up to 1,000 operations/month including webhooks, enough for personal price monitoring.
Use price alert webhooks to drive automations: scenes, notifications or lighting when a tracked product hits your target price.
See Home Assistant and Loxone below.
What it enables: Trigger automations when a Pricewatcha price alert fires.
Typical use case: Price below threshold → mobile notification, toggle input_boolean.good_deal or run a script.
- Add a Webhook trigger (e.g. webhook ID
pricewatcha_price_drop→https://YOUR_HA_HOST/api/webhook/pricewatcha_price_drop). - Ensure the URL is reachable from the internet (Nabu Casa, reverse proxy or tunnel).
- Create a Pricewatcha alert with that
webhook_url(n8n guide shows thecurlexample). - In actions, use
trigger.json.product.name,trigger.json.price.new_price, etc.
Example automation (YAML):
automation:
- alias: "Pricewatcha price drop"
trigger:
- platform: webhook
webhook_id: pricewatcha_price_drop
allowed_methods: [POST]
local_only: false
action:
- service: notify.notify
data:
title: "Price alert: {{ trigger.json.product.name }}"
message: >-
{{ trigger.json.product.shop }} ·
{{ trigger.json.price.new_price }}
{{ trigger.json.product.currency }}rest:
- resource: "https://pricewatcha.com/api/v1/products/prod_YOUR_PRODUCT_ID"
scan_interval: 3600
sensor:
- name: "Tracked product price"
value_template: "{{ value_json.current_price }}"
unit_of_measurement: "EUR"No API key required for read endpoints. Polling is simpler but less real-time than webhooks.
Signature verification: Validate
X-Pricewatcha-Signaturein production: see Webhook signing.
What it enables: Receive price-alert webhooks on your Miniserver and drive programs from virtual inputs.
Typical use case: JSON webhook → virtual input ViPriceAlert pulses → lighting or push notification.
- Add a Virtual HTTP Input in Loxone Config (POST from the internet if reachable).
- Create a Pricewatcha alert with that
webhook_url. - Use command recognition on the raw JSON; map values to your program.
Example patterns for price_alert_triggered (match exact spacing in the monitor):
| Field | Pattern |
|---|---|
| Product name | "name": "\a |
| Current price | "new_price": \v |
| Threshold | "min_threshold_price": \v |
| Event type | "event_type": "\a |
See Loxone Command Recognition.
- Virtual HTTP Output on a schedule.
GET https://pricewatcha.com/api/v1/products/prod_YOUR_PRODUCT_ID- Extract
"current_price": \vvia command recognition.
Remote access: Pricewatcha must reach your webhook URL over HTTPS: use Loxone Remote Connect or a reverse proxy.
Official Python and TypeScript client libraries live in sdks/ on GitHub.
They support the async track → poll → read workflow. Use the OpenAPI schema or plain HTTP from any other language.
from pricewatcha import Pricewatcha
client = Pricewatcha() # public endpoints, no key needed
## With an API key (alerts, webhooks, …)
client = Pricewatcha(api_key="pwk_live_YOUR_KEY")Install from the Python SDK on GitHub. Setup: sdks/python/README.md.
import { PricewatchaClient } from "@pricewatcha/sdk";
const client = new PricewatchaClient(); // public endpoints, no key needed
const authedClient = new PricewatchaClient({ apiKey: "pwk_live_YOUR_KEY" });Install from the TypeScript SDK on GitHub. Setup: sdks/typescript/README.md.
Generate clients in other languages from the OpenAPI spec or live GET https://pricewatcha.com/api/v1/openapi.json (OpenAPI Generator, Speakeasy, Kiota and similar tools).
All notable changes to the public API contract documented in this repository.
v1 is the initial API version. It has not been generally released yet; the items below describe the first public preview contract as a single release.
GET /api/v1/healthGET /api/v1: discovery documentPOST /api/v1/track: async ingestion (200, bounded long-poll ~25s)GET /api/v1/jobs/{jobId}GET /api/v1/products/{productId}GET /api/v1/products/{productId}/price-historyGET /api/v1/search?q=GET /api/v1/openapi.json- Demo catalog:
demo_iphone_15_pro,demo_galaxy_s24 - Rate limit response headers on preview endpoints
- API keys:
POST /api/keys,GET /api/keys,DELETE /api/keys/{id}(pwk_live_...) - Alerts:
POST/GET/PATCH/DELETE /api/v1/alerts(API key required) - Webhooks: full CRUD at
/api/v1/webhooks, test delivery, delivery logs (API key required) - Official MCP server: remote HTTP at
https://mcp.pricewatcha.com(no API key for MCP connection) - Docs: API key as default credential; login session token for headless key bootstrap only
POST /api/v1/trackreturns HTTP 200 with bounded server-side long-poll (~25s); slow jobs returnstatus: "running"for client polling (replaces 202 Accepted)- Search (
GET /api/v1/search) includes the full product catalog, not only API-ingested URLs and demo samples - Product IDs unified to opaque
prod_*in all responses - Privacy model documented: product-level intelligence is public; user-specific data is never exposed
- MCP server status: official (not experimental); tools
track_product+get_job_statusreplace older wait helpers
- Read endpoints remain open without authentication; API keys required for alerts and webhooks
- Endpoints and fields may change before v1 general availability
openapi/ OpenAPI 3.1 specification
docs/ API guides (source for README and Developer page)
examples/ curl and SDK samples
sdks/python/ Official Python package
sdks/typescript/ Official TypeScript package
mcp/ MCP tool schema (reference)
mcp-server/ MCP server (TypeScript)
public-demo/ Demo product IDs
Examples: examples/
MCP: mcp/README.md · mcp-server/
- Public preview: endpoints, fields and rate limits may change.
- Prices are snapshots: always verify on the merchant site.
- Not financial advice: trends are derived from historical data only.
Apache License 2.0: see LICENSE.
Report vulnerabilities responsibly: SECURITY.md.
Questions about the API, integration issues or unexpected behaviour: support@pricewatcha.com.
For bugs or documentation fixes in this repository, open a GitHub issue.