# Product price tracking

Your products on Google Shopping and Amazon: on the shelf or not, position, the cheapest comparable listing and how far above it you are.

## Product price tracking: plan and usage

`GET /product-tracking` · scope `products:read`

Your plan, how many products it covers and how your products are doing on the shelves.

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/product-tracking" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/product-tracking", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/product-tracking", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "plan": "Product price tracking + 1 x +25 products",
    "unlimited": false,
    "paid_until": "2026-10-25",
    "products": 12,
    "products_included": 35,
    "listed": 9,
    "not_listed": 3,
    "undercut": 2,
    "price_from": "15.00"
  }
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## List your tracked products

`GET /product-tracking/products` · scope `products:read`

Every product you track, with the latest reading of each shelf.

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/product-tracking/products" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/product-tracking/products", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/product-tracking/products", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": [
    {
      "id": 41,
      "title": "Sony WH-1000XM5",
      "country": "GB",
      "asin": "B09Y2MYL5C",
      "sku": "WH1000XM5B",
      "competitor": false,
      "covered_by_plan": true,
      "shelves": [
        {
          "shelf": "google",
          "state": "ok",
          "listed": true,
          "position": 3,
          "your_price": "229.00",
          "cheapest_price": "199.99",
          "cheapest_seller": "Argos",
          "currency": "GBP",
          "gap_percent": "14.51",
          "listings": 20,
          "comparable": 12,
          "last_read_at": "2026-09-26T11:40:00Z"
        }
      ]
    }
  ]
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## One product

`GET /product-tracking/products/{product_id}` · scope `products:read`

One product with every listing we read on each shelf ("counted" = comparable to your product; "yours" = recognised by your seller name or ASIN).

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `product_id` | path | integer | yes | The product id. |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/product-tracking/products/product_id" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/product-tracking/products/product_id", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/product-tracking/products/product_id", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "id": 41,
    "title": "Sony WH-1000XM5",
    "country": "GB",
    "asin": "B09Y2MYL5C",
    "sku": "WH1000XM5B",
    "competitor": false,
    "covered_by_plan": true,
    "shelves": [
      {
        "shelf": "google",
        "state": "ok",
        "listed": true,
        "position": 3,
        "your_price": "229.00",
        "cheapest_price": "199.99",
        "cheapest_seller": "Argos",
        "currency": "GBP",
        "gap_percent": "14.51",
        "listings": 20,
        "comparable": 12,
        "last_read_at": "2026-09-26T11:40:00Z"
      }
    ],
    "listings": {
      "google": [
        {
          "position": 1,
          "title": "Sony WH-1000XM5 Wireless",
          "seller": "Argos",
          "price": "199.99",
          "currency": "GBP",
          "yours": false,
          "counted": true,
          "cheapest": true
        }
      ]
    }
  }
}
```

Errors: `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## Track a product

`POST /product-tracking/products` · scope `products:write`

Adds a product and reads both shelves at once. Refused before anything is spent if your plan has no room.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `title` | body | string | yes | The product the way shoppers search for it, e.g. "Sony WH-1000XM5". |
| `country` | body | string (one of: GB, US, DE, FR, ES, IT, CA, AU) | yes | The country you sell it in (the list is kept by us and may grow). |
| `asin` | body | string | no | Your Amazon ASIN for it, to recognise your listing. |
| `sku` | body | string | no | Your SKU or GTIN (for your own reference). |
| `competitor` | body | boolean | no | True for a competitor's product (watched, never "yours"). Default: `False`. |

### Example

```bash
curl -s -X POST "https://app.pbn.ltd/api/v1/product-tracking/products" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/product-tracking/products", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/product-tracking/products", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`201`

```json
{
  "data": {
    "id": 41,
    "title": "Sony WH-1000XM5",
    "country": "GB",
    "asin": "B09Y2MYL5C",
    "sku": "WH1000XM5B",
    "competitor": false,
    "covered_by_plan": true,
    "shelves": [
      {
        "shelf": "google",
        "state": "ok",
        "listed": true,
        "position": 3,
        "your_price": "229.00",
        "cheapest_price": "199.99",
        "cheapest_seller": "Argos",
        "currency": "GBP",
        "gap_percent": "14.51",
        "listings": 20,
        "comparable": 12,
        "last_read_at": "2026-09-26T11:40:00Z"
      }
    ]
  }
}
```

Errors: `payment_required`, `rate_limited`, `scope_missing`, `unauthorized`, `validation_failed`

## Stop tracking a product

`DELETE /product-tracking/products/{product_id}` · scope `products:write`

Removes the product and its history.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `product_id` | path | integer | yes | The product id. |

### Example

```bash
curl -s -X DELETE "https://app.pbn.ltd/api/v1/product-tracking/products/product_id" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.delete("https://app.pbn.ltd/api/v1/product-tracking/products/product_id", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/product-tracking/products/product_id", {
  method: "DELETE",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "deleted": true
  }
}
```

Errors: `not_found`, `rate_limited`, `scope_missing`, `unauthorized`
