Documentation

Product Healer API

A REST API over your own data, for spreadsheets, dashboards and scripts. Every endpoint reads, except POST /api/v1/extension/track, which starts tracking a product and needs a token created with the read/write scope. Included with the Enterprise plan (see pricing).

Authentication

Every request carries a bearer token, created at /account/api. A token is shown once when you create it; we store only a hash, so it cannot be recovered.

curl -H "Authorization: Bearer ph_YOUR_TOKEN" \
     https://producthealer.tech/api/v1/tracked

Clients that cannot set an Authorization header may send X-PH-Token instead.

Rate limits

Counted per token, per minute — 60 by default, and your plan may allow more. Every reply carries the current position:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59

Going over returns 429 with a Retry-After header in seconds. Nothing is charged for a refused request.

Endpoints

MethodPathWhat it returnsParameters
GET /api/v1 What this token can reach, and its rate limit. —
GET /api/v1/keywords Your keyword bank, grouped by keyword and market.
market optional, e.g. uk
limit 1-200, default 50
page default 1
GET /api/v1/hunts Your hunt history.
limit 1-200
page default 1
GET /api/v1/products Products saved in your workspace. Unlike the rest of the API, sell_price, cost_price, shipping_cost and ad_cost are MAJOR-unit decimal strings ("21.99"), in the currency of the product's market (uk GBP, us USD, de/fr/it/es/nl EUR, ae AED, sa SAR, eg EGP) - there is no currency field. A price never entered reads "0.00", not null. fee_pct is a percentage.
market optional
limit 1-200
page default 1
GET /api/v1/tracked Tracked products: current figures, our estimate, and the change since tracking began.
market optional
limit 1-200
GET /api/v1/tracked/{asin} One tracked product with its daily history.
days 1-730, default 90
GET /api/v1/alerts Alerts raised for your workspace.
limit 1-200
GET /api/v1/suppliers Your supplier quotes, cheapest landed cost first. unit_cost and shipping_cost are MAJOR-unit decimal strings ("4.50") in the currency of the quote's product market (the market field; no currency field). An unset unit_cost reads "0.00"; unknown shipping is null.
limit 1-200
GET /api/v1/rank Keyword rank-tracking positions.
market optional
limit 1-200
GET /api/v1/fulfilment/stock UK Fulfilment: each product at our warehouse - on hand, in orders, available, damaged, on the way, and its size band (null when no size was given). Needs an active fulfilment account. —
GET /api/v1/fulfilment/orders UK Fulfilment: the newest 200 orders sent to the warehouse with status, delivery service, courier and tracking, whether it is express and any hold-until date. Never the buyer's name or address. —
POST /api/v1/fulfilment/orders UK Fulfilment: send an order from any platform to our warehouse. JSON body: {"reference": "your order number", "items": [{"sku": "MUG-1", "qty": 2}], "address": {"name", "line1", "line2", "city", "region", "postcode", "country": "GB", "phone"} (in the UAE: the emirate as "region", no postcode, a phone number), "cash_on_delivery": "optional, the amount to collect in your warehouse's currency, where it offers it", "buyer_email": "optional - when you have switched dispatch emails on, the buyer gets one email when it leaves; kept encrypted and deleted with the address", "service": "optional, one of our delivery services", "gift_note": "optional, printed on a card, no prices in the parcel", "express": "optional true - dispatched first, same day up to our express cut-off", "hold_until": "optional YYYY-MM-DD - we keep it until that day", "preorder": "optional true - wait for the stock instead of going on hold"} - or {"orders": [...]} with up to 50. Each result carries the buyer's tracking page address. Needs a read/write token. UK addresses unless we have switched international delivery on for you (then the country code, a service that goes there and customs details on every product); every SKU must be one of your fulfilment products. Sending the same reference again does nothing. The address is kept encrypted and deleted 30 days after dispatch. —
GET /api/v1/fulfilment/inbound UK Fulfilment: your deliveries to the warehouse and what was counted (null until counted). —
GET /api/v1/extension/lookup One product with fees and our estimate. Used by the browser extension.
asin required
market required
POST /api/v1/extension/track Start tracking a product. Needs a read/write token.
asin in the JSON body
market in the JSON body

How to read the numbers

Every response separates what was observed from what we estimated, and they are never merged into one field.

  • observed — reported by a data provider, with observed_at saying when.
  • estimate — ours, from sales rank, with a confidence and a note. It is an order of magnitude, not a forecast.
  • null — we do not know. It never means zero, and you should not treat it as zero.
  • Keyword positions are autocomplete positions: a demand signal, not search volume. No endpoint returns a search volume, because no source gives us one.

A worked example

$ curl -s -H "Authorization: Bearer ph_…" \
    https://producthealer.tech/api/v1/tracked

{
  "ok": true,
  "meta": { "page": 1, "limit": 50, "returned": 1 },
  "tracked": [
    {
      "asin": "B0…",
      "marketplace": "uk",
      "title": "…",
      "is_mine": true,
      "observed": {
        "price_minor": 2199, "currency": "GBP", "bsr": 2600,
        "rating": 4.4, "reviews": 344, "sellers": 9,
        "observed_at": "2026-09-22 06:10:04"
      },
      "estimate": {
        "low": 120, "high": 230, "confidence": "low", "label": "120–230",
        "caveat": "Estimated from sales rank. Not a measurement."
      },
      "since_tracking": {
        "price_minor": -300, "bsr_improved_by": 1600,
        "reviews": 26, "sellers": 3, "since": "2026-09-01 09:12:00"
      }
    }
  ]
}

Money here is in minor units — 2199 is £21.99 — so no rounding happens between us and you. Two older endpoints differ: /api/v1/products and /api/v1/suppliers return major-unit decimal strings (see their entries above). estimate is monthly units as a low–high range, never a single number, and is null when the sales rank is missing or outside the range our model covers.

MCP server (for AI assistants)

AI tools that speak the Model Context Protocol (such as Claude) can read your Product Healer data directly. Add a remote MCP server with the address https://producthealer.tech/mcp and your API token as a Bearer token (Authorization: Bearer ph_...). It uses the same token, plan check and per-minute limit as this API, is read-only, and spends no lookups: it reads what your workspace already holds.

list_tracked_productsProducts this workspace tracks, with current price, rank, sellers and the change since tracking started.
get_productThe figures this workspace already holds for one ASIN (from Keepa, the seller's Amazon account or typed in). Spends no lookup; says when nothing is held.
search_keyword_bankKeywords in this workspace's keyword bank. Positions are autocomplete positions - a demand signal, not search volume.
list_alertsRecent alerts raised for this workspace (prices, ranks, stock, profit and more).
search_query_performanceAmazon Search Query Performance (Brand Analytics) from the latest collected report: queries, Amazon's own search counts and this brand's share of clicks and purchases.
amazon_search_termsAmazon Search Terms (Brand Analytics) from the latest collected report: the most-searched terms and the products taking the clicks.
price_list_resultsResults of the latest Price List Scanner list (or a given one): each supplier line with its Amazon match, price, profit, ROI and verdict.

A tool that is not in your plan is not offered. Transport: Streamable HTTP, POST only, answered with JSON (no event stream).

Errors

401No token, or the token is not recognised, revoked or expired.
403The account is suspended, the token lacks the scope for that call, the plan does not include it, or the plan's monthly allowance for it (for example product lookups) is used up — the error says which. Retrying will not help until the allowance resets.
404No such endpoint, or you are not tracking that ASIN.
409The call is valid but cannot be served yet — usually a data provider is not connected.
429Per-minute rate limit for the token. Wait for Retry-After seconds.

Every error reply is JSON with ok: false and a human-readable error. There is no error format to special-case.