Skip to content

API reference

Every endpoint of the Data API, generated from its OpenAPI document. Each answer is JSON unless it says otherwise.

Base URL
https://pricana.io/api/v1
Authentication
Your API key as a bearer token: Authorization: Bearer prc_live_…. Live keys read your datasets, test keys only the sample datasets. Create keys in the portal (API).
OpenAPI document
OpenAPI 3.1.0 (Pricana Data API v1)

Requests go to this server with your key. The key stays in this page’s memory only.

Datasets

What you can read: your datasets and the values to filter them by.

GET /api/v1/datasets

Your datasets

The datasets your plan lets you read, with how many items and websites each has and when its sources were last read. Their id is the dataset filter of the other requests.

Responses

  • 200 Your datasets. application/json Dataset[]
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

[
  {
    "description": "Laptops and notebooks from shops in Germany, Austria and Switzerland.",
    "healthyModels": 14,
    "id": 12,
    "items": 18342,
    "models": 14,
    "name": "Laptops DACH",
    "newestScrapeAt": "2026-10-07T09:12:00Z",
    "oldestScrapeAt": "2026-10-07T05:40:00Z",
    "sites": 9
  }
]
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/datasets"
Try it

GET /api/v1/facets

Websites, categories and currencies to filter by

The values the items can be filtered by, each with the number of items listed now.

Parameters

NameTypeDescription
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12

Responses

  • 200 The facets. application/json Facets
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 404 No such dataset of yours. application/json Error
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "categories": [
    {
      "id": 8,
      "items": 1804,
      "name": "Laptops",
      "parentId": 2,
      "path": "Computers > Laptops",
      "slug": "computers-laptops"
    }
  ],
  "currencies": [
    {
      "code": "EUR",
      "items": 17920
    }
  ],
  "sites": [
    {
      "host": "www.notebookshop.example",
      "id": 4,
      "items": 2310,
      "name": "Notebookshop"
    }
  ]
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/facets"
Try it

Items

Listings as they are now, and their history.

GET /api/v1/items

Find items

Items of your datasets, filtered and sorted, a page at a time (up to 500). To keep a copy in sync, use the change feed (/changes) or changedSince.

Parameters

NameTypeDescription
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
site
query
integerOnly items of this website (id from /facets).
Example: 4
category
query
stringA category's slug (from /facets), with its subcategories.
Example: computers-laptops
q
query
stringWords to look for (all of them, in any order) in the title, brand, codes and other values of the item; parts of words count.
Example: thinkpad x1
minPrice
query
numberLowest price, in the item's currency.
Example: 500
maxPrice
query
numberHighest price, in the item's currency.
Example: 1500
currency
query
stringISO 4217 code.
Example: EUR
status
query
string, one of active, removed, allactive (listed now, the default), removed (no longer listed) or all.
changedSince
query
string (date-time)Only items with a change after this time (ISO 8601), e.g. the start of your last sync.
Example: 2026-10-01T00:00:00Z
gtin
query
stringEAN/UPC/ISBN-13: the same product in every shop (leading zeros may be left out).
Example: 0196802123456
sort
query
string, one of price, -price, -lastChanged, -lastSeen, -firstSeen, titleprice, -price (highest first), -lastChanged (the default), -lastSeen, -firstSeen (newest listings first) or title.
page
query
integerThe page, from 0.
Example: 0
default: 0
size
query
integerItems per page, 1 to 500.
Example: 100
default: 50

Responses

  • 200 A page of items. application/json PageDtoItem
  • 400 A parameter is not valid; message says which. application/json Error
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "content": [
    {
      "attributes": {
        "availability": "in stock",
        "shipping": 0
      },
      "brand": "Lenovo",
      "category": {
        "name": null,
        "path": null,
        "slug": null,
        "source": null
      },
      "currency": "EUR",
      "datasets": [
        "Laptops DACH"
      ],
      "firstSeenAt": "2026-09-01T10:00:00Z",
      "gtin": "0196802123456",
      "id": 77,
      "image": "https://www.notebookshop.example/img/thinkpad-x1.jpg",
      "lastChangedAt": "2026-10-06T21:03:00Z",
      "lastSeenAt": "2026-10-07T09:12:00Z",
      "mpn": "21KC004MGE",
      "previousPrice": 1499,
      "price": 1399,
      "priceChangedAt": "2026-10-06T21:03:00Z",
      "removedAt": "2026-10-07T03:30:00Z",
      "site": {
        "attribution": null,
        "host": null,
        "id": null,
        "name": null
      },
      "source": {
        "modelId": null,
        "name": null
      },
      "title": "Lenovo ThinkPad X1 Carbon Gen 12",
      "url": "https://www.notebookshop.example/p/thinkpad-x1"
    }
  ],
  "page": 0,
  "size": 50,
  "totalElements": 1804,
  "totalPages": 37
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/items"
Try it

GET /api/v1/items/{id}

One item

The item as it is now (as /items shows it), also once it is no longer listed.

Parameters

NameTypeDescription
id
path, required
integerThe item's id.
Example: 77

Responses

  • 200 The item. application/json Item
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 404 Not found among the items you can see. application/json Error
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "attributes": {
    "availability": "in stock",
    "shipping": 0
  },
  "brand": "Lenovo",
  "category": {
    "name": "Laptops",
    "path": "Computers > Laptops",
    "slug": "computers-laptops",
    "source": "AI"
  },
  "currency": "EUR",
  "datasets": [
    "Laptops DACH"
  ],
  "firstSeenAt": "2026-09-01T10:00:00Z",
  "gtin": "0196802123456",
  "id": 77,
  "image": "https://www.notebookshop.example/img/thinkpad-x1.jpg",
  "lastChangedAt": "2026-10-06T21:03:00Z",
  "lastSeenAt": "2026-10-07T09:12:00Z",
  "mpn": "21KC004MGE",
  "previousPrice": 1499,
  "price": 1399,
  "priceChangedAt": "2026-10-06T21:03:00Z",
  "removedAt": "2026-10-07T03:30:00Z",
  "site": {
    "attribution": "Source: European Commission, Weekly Oil Bulletin, CC BY 4.0",
    "host": "www.notebookshop.example",
    "id": 4,
    "name": "Notebookshop"
  },
  "source": {
    "modelId": 31,
    "name": "Notebookshop – Laptops"
  },
  "title": "Lenovo ThinkPad X1 Carbon Gen 12",
  "url": "https://www.notebookshop.example/p/thinkpad-x1"
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/items/77"
Try it

GET /api/v1/items/{id}/history

An item's history

Every change of the item within your plan's history, oldest first: its prices over time.

Parameters

NameTypeDescription
id
path, required
integerThe item's id.
Example: 77

Responses

  • 200 The item's history. application/json HistoryEntry[]
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 404 Not found among the items you can see. application/json Error
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

[
  {
    "changes": {
      "availability": [
        "2-3 days",
        "in stock"
      ]
    },
    "id": 812,
    "kind": "NEW",
    "observedAt": "2026-10-06T21:03:00Z",
    "previousPrice": 1499,
    "price": 1399
  }
]
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/items/77/history"
Try it

Changes

Every new item, change and removal, in order: to keep a copy in sync.

GET /api/v1/changes

The change feed

Everything that happened after after, oldest first. Start with after=0, then pass each answer's nextCursor as after; repeat while hasMore is true. Store the last cursor and go on from it next time: you get each change exactly once. Changes show here about 30 seconds after they happen. Paid plans (on Free it answers 402).

Parameters

NameTypeDescription
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
after
query
integerThe cursor: the nextCursor of the last answer (0 = from the beginning of your plan's history).
Example: 0
default: 0
limit
query
integerChanges per answer, 1 to 1000.
Example: 1000
default: 500

Responses

  • 200 The next changes. application/json ChangePage
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "changes": [
    {
      "changes": {
        "price": [
          1499,
          1399
        ]
      },
      "id": 812,
      "item": {
        "currency": null,
        "id": null,
        "site": null,
        "title": null,
        "url": null
      },
      "kind": "NEW",
      "observedAt": "2026-10-06T21:03:00Z",
      "previousPrice": 1499,
      "price": 1399
    }
  ],
  "hasMore": true,
  "nextCursor": 1811
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/changes"
Try it

GET /api/v1/changes/recent

Recent changes, newest first

For people: the latest changes, newest first, optionally only of one kind. Page back with before. To sync a copy, use /changes. A change shows here when it shows in /changes (within about 30 seconds), so the id of the newest one is a safe place to start /changes?after= from.

Parameters

NameTypeDescription
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
kind
query
string, one of NEW, CHANGED, REMOVED, RELISTED, PRICE_DROP, PRICE_RISENEW, CHANGED, REMOVED, RELISTED, PRICE_DROP or PRICE_RISE.
before
query
integerThe last id of the previous page.
Example: 1811
limit
query
integerChanges per answer, 1 to 200.
Example: 50
default: 50

Responses

  • 200 The changes. application/json ChangePage
  • 400 A parameter is not valid; message says which. application/json Error
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "changes": [
    {
      "changes": {
        "price": [
          1499,
          1399
        ]
      },
      "id": 812,
      "item": {
        "currency": null,
        "id": null,
        "site": null,
        "title": null,
        "url": null
      },
      "kind": "NEW",
      "observedAt": "2026-10-06T21:03:00Z",
      "previousPrice": 1499,
      "price": 1399
    }
  ],
  "hasMore": true,
  "nextCursor": 1811
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/changes/recent"
Try it

Products

The same product across shops: compare its prices.

GET /api/v1/products

Find products across shops

Products with offers in your datasets: the same product in several shops, matched by GTIN, else by brand and part number, with its price range and how many shops sell it.

Parameters

NameTypeDescription
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
q
query
stringWords to look for (all of them, in any order) in the title, brand, codes and other values of the item; parts of words count.
Example: thinkpad
category
query
stringA category's slug (from /facets), with its subcategories.
Example: computers-laptops
brand
query
stringThe brand, as the shops name it.
Example: Lenovo
gtin
query
stringEAN/UPC/ISBN-13: the same product in every shop (leading zeros may be left out).
Example: 0196802123456
currency
query
stringISO 4217 code.
Example: EUR
minShops
query
integerSold by at least this many websites (2: products to compare).
Example: 2
default: 1
sort
query
string, one of -offers, -shops, price, -price-offers (the default), -shops, price (lowest first) or -price.
page
query
integerThe page, from 0.
Example: 0
default: 0
size
query
integerProducts per page, 1 to 200.
Example: 50
default: 50

Responses

  • 200 A page of products. application/json PageDtoProduct
  • 400 A parameter is not valid; message says which. application/json Error
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "content": [
    {
      "brand": "Lenovo",
      "category": {
        "name": null,
        "path": null,
        "slug": null,
        "source": null
      },
      "gtin": "0196802123456",
      "id": "0196802123456",
      "mpn": "21KC004MGE",
      "offers": 6,
      "prices": [
        null
      ],
      "shops": 5,
      "title": "Lenovo ThinkPad X1 Carbon Gen 12"
    }
  ],
  "page": 0,
  "size": 50,
  "totalElements": 1804,
  "totalPages": 37
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/products"
Try it

GET /api/v1/products/{id}

One product with its offers

A product by its id (a GTIN, or a brand-MPN key) with all its offers you can see, cheapest first.

Parameters

NameTypeDescription
id
path, required
stringThe product's id: a GTIN (any of its forms) or a brand-MPN key.
Example: 0196802123456
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
currency
query
stringOnly offers in this currency (ISO 4217).
Example: EUR

Responses

  • 200 The product and its offers. application/json ProductDetail
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 404 No offers of this product among the items you can see. application/json Error
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "offers": [
    {
      "attributes": {
        "availability": "in stock",
        "shipping": 0
      },
      "brand": "Lenovo",
      "category": {
        "name": null,
        "path": null,
        "slug": null,
        "source": null
      },
      "currency": "EUR",
      "datasets": [
        "Laptops DACH"
      ],
      "firstSeenAt": "2026-09-01T10:00:00Z",
      "gtin": "0196802123456",
      "id": 77,
      "image": "https://www.notebookshop.example/img/thinkpad-x1.jpg",
      "lastChangedAt": "2026-10-06T21:03:00Z",
      "lastSeenAt": "2026-10-07T09:12:00Z",
      "mpn": "21KC004MGE",
      "previousPrice": 1499,
      "price": 1399,
      "priceChangedAt": "2026-10-06T21:03:00Z",
      "removedAt": "2026-10-07T03:30:00Z",
      "site": {
        "attribution": null,
        "host": null,
        "id": null,
        "name": null
      },
      "source": {
        "modelId": null,
        "name": null
      },
      "title": "Lenovo ThinkPad X1 Carbon Gen 12",
      "url": "https://www.notebookshop.example/p/thinkpad-x1"
    }
  ],
  "product": {
    "brand": "Lenovo",
    "category": {
      "name": "Laptops",
      "path": "Computers > Laptops",
      "slug": "computers-laptops",
      "source": "AI"
    },
    "gtin": "0196802123456",
    "id": "0196802123456",
    "mpn": "21KC004MGE",
    "offers": 6,
    "prices": [
      {
        "currency": null,
        "max": null,
        "min": null,
        "offers": null
      }
    ],
    "shops": 5,
    "title": "Lenovo ThinkPad X1 Carbon Gen 12"
  }
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/products/0196802123456"
Try it

Export

Everything at once, as CSV or NDJSON.

GET /api/v1/export

Export items

All matching items, streamed as CSV (UTF-8, a header row) or NDJSON (one JSON object per line), with the filters of /items. Rows count against your plan's export rows per month. On paid plans, rows beyond them are billed as overage per started 10,000 and the export is complete (X-Export-Overage); on Free, in the trial, or with overage switched off, an export that would go beyond them ends at the limit and says so in X-Export-Truncated.

Parameters

NameTypeDescription
format
query
string, one of csv, ndjsoncsv (the default) or ndjson.
dataset
query
integerOne of your datasets (its id from /datasets); without it, all of them.
Example: 12
site
query
integerOnly items of this website (id from /facets).
Example: 4
category
query
stringA category's slug (from /facets), with its subcategories.
Example: computers-laptops
q
query
stringWords to look for (all of them, in any order) in the title, brand, codes and other values of the item; parts of words count.
Example: thinkpad
minPrice
query
numberLowest price, in the item's currency.
Example: 500
maxPrice
query
numberHighest price, in the item's currency.
Example: 1500
currency
query
stringISO 4217 code.
Example: EUR
status
query
string, one of active, removed, allactive (listed now, the default), removed (no longer listed) or all.
changedSince
query
string (date-time)Only items with a change after this time (ISO 8601), e.g. the start of your last sync.
Example: 2026-10-01T00:00:00Z
gtin
query
stringEAN/UPC/ISBN-13: the same product in every shop (leading zeros may be left out).
Example: 0196802123456

Responses

  • 200 The rows, streamed. application/x-ndjson string text/csv string
    • X-Export-Matching: With X-Export-Truncated: how many rows matched.
    • X-Export-Overage: true if rows beyond the month's quota are in it, billed as overage.
    • X-Export-Rows: Rows in this export.
    • X-Export-Rows-Remaining: Export rows left this month after it.
    • X-Export-Truncated: true if the export ended at the monthly limit.
  • 400 A parameter is not valid; message says which. application/json Error
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/export"
Try it

Only the start of the answer is read and shown, and the export stops there; the rows it wrote still count against your month’s export rows. Filters keep it small.

Plan

Your plan, its limits and this month's use.

GET /api/v1/plan

Your plan and this month's use

The plan in effect, its limits (null is unlimited), the calls and export rows used this month and when they start over. Every answer also carries RateLimit-* and X-Quota-* headers.

Responses

  • 200 Your plan. application/json PlanInfo
  • 401 No API key, or one that is invalid or revoked. application/json Error
  • 402 Not in your plan (a dataset beyond it, the change feed on Free), or a payment overdue for 30 days (limit: paymentOverdue). application/json LimitError
  • 429 Too many requests per second, or the month's calls are used up (limit says which). Retry-After says when to try again. application/json LimitError

Example

{
  "limits": {
    "datasets": 10,
    "apiCallsPerMonth": 250000,
    "ratePerSecond": 20,
    "delayHours": 0,
    "historyDays": 365,
    "exportRowsPerMonth": 1000000,
    "changeFeed": true,
    "webhooks": true
  },
  "lockedDatasets": 0,
  "name": "Pro",
  "plan": "pro",
  "status": "ACTIVE",
  "trialEndsAt": "2026-10-21T09:00:00Z",
  "upgradeUrl": "https://pricana.io/pricing",
  "usage": {
    "apiCalls": 48211,
    "exportRows": 12000,
    "resetsAt": "2026-11-01T00:00:00Z"
  }
}
curl -H "Authorization: Bearer $PRICANA_KEY" \
  "https://pricana.io/api/v1/plan"
Try it

Webhooks

Pricana sends these to your endpoint. Set endpoints up in the portal (API); the guide explains the signature. Webhooks guide

POST https://your-server.example/…

New changes of the change feed (sent by Pricana)

Pricana posts the next changes of your datasets to your endpoint, in order, up to 100 at a time, as the change feed lists them (type: changes), and a test when you send one from the portal (type: ping). Check the signature before you use the body: HMAC-SHA256 with your endpoint's secret over <t>.<body>, compared with each v1 value. Answer with any 2xx within 10 seconds; anything else is tried again after 1, 5, 15 and 30 minutes, then 1, 2 and every 4 hours, and later changes wait. After 24 hours of failures the endpoint is turned off and your team gets an email.

Parameters

NameTypeDescription
Pricana-Signature
header, required
stringt=<unix seconds>,v1=<hex HMAC-SHA256>; a second v1 while a rolled secret's old one is still valid.
Example: t=1791374400,v1=26ff918ca24488a1a2aa21935c219eaed5c31c721399ca4d400ebecf2784fdf4
Pricana-Event-Id
header, required
stringThe event's id, as id in the body.
Example: evt_5f1c0b2a9d7e4c3b8a6f0e1d
Pricana-Event-Type
header, required
stringchanges or ping.
Example: changes
Pricana-Delivery-Attempt
header, required
integer1 for the first attempt, then 2, 3 …
Example: 1

Body Pricana sends: WebhookEvent

{
  "changes": [
    {
      "changes": {
        "price": [
          1499,
          1399
        ]
      },
      "id": 812,
      "item": {
        "currency": null,
        "id": null,
        "site": null,
        "title": null,
        "url": null
      },
      "kind": "NEW",
      "observedAt": "2026-10-06T21:03:00Z",
      "previousPrice": 1499,
      "price": 1399
    }
  ],
  "createdAt": "2026-10-07T09:12:31Z",
  "cursor": 1811,
  "id": "evt_5f1c0b2a9d7e4c3b8a6f0e1d",
  "type": "changes"
}

Responses

  • 200 Received (any 2xx will do; the body is ignored).
  • default Anything else (and no answer in 10 seconds): tried again later.

Data model

CategoryRef

The item's category in Pricana's taxonomy.

NameTypeDescription
namestring
Example: "Laptops"
pathstring
Example: "Computers > Laptops"
slugstring
Example: "computers-laptops"
sourcestring, one of AI, MANUALWho chose it (EU AI Act transparency): AI, or MANUAL (a person).
Example: "AI"

Change

One entry of the change feed: an item appeared (NEW), changed (CHANGED), was no longer listed (REMOVED) or came back (RELISTED). id is the cursor.

NameTypeDescription
changesobjectValues that changed, by name: [old, new].
Example: {"price":[1499,1399]}
idintegerIncreasing: pass the last one you have as after.
Example: 812
itemChangeItemNull if the item is gone from your data meanwhile.
kindstring, one of NEW, CHANGED, REMOVED, RELISTED
observedAtstring (date-time)
Example: "2026-10-06T21:03:00Z"
previousPricenumber | nullSet when the price changed.
Example: 1499
pricenumber | null
Example: 1399

ChangeItem

The item a change belongs to (its title and link then).

NameTypeDescription
currencystring | null
Example: "EUR"
idinteger
Example: 77
siteSiteRef
titlestring
Example: "Lenovo ThinkPad X1 Carbon Gen 12"
urlstring | null
Example: "https://www.notebookshop.example/p/thinkpad-x1"

ChangePage

A page of changes. Pass nextCursor on to get the next entries: as after to /changes, as before to /changes/recent.

NameTypeDescription
changesChange[]
hasMorebooleanMore changes are waiting now: ask again at once.
Example: true
nextCursorintegerStore it, and continue from it next time (after for /changes, before for /changes/recent).
Example: 1811

Dataset

A dataset: the listings of a set of websites on one topic, as your plan shows them.

NameTypeDescription
descriptionstring | null
Example: "Laptops and notebooks from shops in Germany, Austria and Switzerland."
healthyModelsintegerSources collecting without problems; the others are being repaired.
Example: 14
idintegerUse it as dataset in other requests.
Example: 12
itemsintegerItems listed now.
Example: 18342
modelsintegerSources: one listing of one website each.
Example: 14
namestring
Example: "Laptops DACH"
newestScrapeAtstring (date-time) | nullWhen a source of the dataset was last read; null before the first.
Example: "2026-10-07T09:12:00Z"
oldestScrapeAtstring (date-time) | nullWhen the source read longest ago was read.
Example: "2026-10-07T05:40:00Z"
sitesintegerWebsites the items come from.
Example: 9

Error

Every error answer.

NameTypeDescription
docsUrlstringThe docs' page about this error.
Example: "https://pricana.io/docs/errors#not-found"
errorstring
Example: "Not Found"
messagestring
Example: "Item 77 not found"
statusinteger
Example: 404

FacetCategory

A category among the facets, with its items (subcategories included).

NameTypeDescription
idinteger
Example: 8
itemsinteger
Example: 1804
namestring
Example: "Laptops"
parentIdinteger | nullNull for a top category.
Example: 2
pathstring
Example: "Computers > Laptops"
slugstring
Example: "computers-laptops"

FacetCurrency

A currency among the facets, with its items.

NameTypeDescription
codestring
Example: "EUR"
itemsinteger
Example: 17920

Facets

What the items can be filtered by, with counts.

NameTypeDescription
categoriesFacetCategory[]
currenciesFacetCurrency[]
sitesFacetSite[]

FacetSite

A website among the facets, with its items.

NameTypeDescription
hoststring
Example: "www.notebookshop.example"
idinteger
Example: 4
itemsinteger
Example: 2310
namestring
Example: "Notebookshop"

HistoryEntry

One step in an item's history.

NameTypeDescription
changesobjectValues that changed, by name: [old, new].
Example: {"availability":["2-3 days","in stock"]}
idinteger
Example: 812
kindstring, one of NEW, CHANGED, REMOVED, RELISTED
observedAtstring (date-time)
Example: "2026-10-06T21:03:00Z"
previousPricenumber | nullSet when the price changed.
Example: 1499
pricenumber | null
Example: 1399

Item

A listing (an offer of a product in a shop), as it is now: the shop's own values, with Pricana's category and the product codes that identify it across shops.

NameTypeDescription
attributesobjectFurther values the shop shows (stock, shipping, ratings …), by name.
Example: {"availability":"in stock","shipping":0}
brandstring | null
Example: "Lenovo"
categoryCategoryRefNull while it has none.
currencystring | null
Example: "EUR"
datasetsstring[]Your datasets the item is in.
Example: ["Laptops DACH"]
firstSeenAtstring (date-time)
Example: "2026-09-01T10:00:00Z"
gtinstring | nullEAN/UPC/ISBN-13 (8, 13 or 14 digits): the same product in every shop. Null when the shop doesn't name it.
Example: "0196802123456"
idinteger
Example: 77
imagestring | nullThe shop's product image, if it shows one.
Example: "https://www.notebookshop.example/img/thinkpad-x1.jpg"
lastChangedAtstring (date-time)The last time a value changed (use it with changedSince).
Example: "2026-10-06T21:03:00Z"
lastSeenAtstring (date-time)The last time a scrape found it.
Example: "2026-10-07T09:12:00Z"
mpnstring | nullThe manufacturer's part number.
Example: "21KC004MGE"
previousPricenumber | nullThe price before the last price change; null if it never changed.
Example: 1499
pricenumber | nullNull when the shop shows none.
Example: 1399
priceChangedAtstring (date-time) | nullWhen the price last changed.
Example: "2026-10-06T21:03:00Z"
removedAtstring (date-time) | nullWhen the shop stopped listing it; null while it is listed.
Example: "2026-10-07T03:30:00Z"
siteSiteRef
sourceSource
titlestring | null
Example: "Lenovo ThinkPad X1 Carbon Gen 12"
urlstring | nullThe item's page in the shop.
Example: "https://www.notebookshop.example/p/thinkpad-x1"

LimitError

A plan limit (402) or a rate or monthly limit (429): which one, its value in your plan, and where to upgrade.

NameTypeDescription
allowedobjectIts value in your plan.
Example: 100000
docsUrlstring
Example: "https://pricana.io/docs/errors#apiCallsPerMonth"
errorstring
Example: "Too Many Requests"
limitstringThe limit: datasets, changeFeed, apiCallsPerMonth, ratePerSecond, exportRowsPerMonth or paymentOverdue.
Example: "apiCallsPerMonth"
messagestring
Example: "The monthly quota of 100,000 calls is used up; it starts over on 1 November"
planstring
Example: "pro"
statusinteger
Example: 429
upgradeUrlstring
Example: "https://pricana.io/pricing"

PageDtoItem

A page of results.

NameTypeDescription
contentItem[]
pageintegerThis page, from 0.
Example: 0
sizeintegerResults per page.
Example: 50
totalElementsintegerAll results.
Example: 1804
totalPagesintegerPages in all.
Example: 37

PageDtoProduct

A page of results.

NameTypeDescription
contentProduct[]
pageintegerThis page, from 0.
Example: 0
sizeintegerResults per page.
Example: 50
totalElementsintegerAll results.
Example: 1804
totalPagesintegerPages in all.
Example: 37

PlanInfo

Your plan in effect (Free once a trial ended), its limits and this month's use.

NameTypeDescription
limitsobjectThe limits by name; null is unlimited.
Example: {"datasets":10,"apiCallsPerMonth":250000,"ratePerSecond":20,"delayHours":0,"historyDays":365,"exportRowsPerMonth":1000000,"changeFeed":true,"webhooks":true}
lockedDatasetsintegerYour datasets beyond what the plan includes: they answer 402.
Example: 0
namestring
Example: "Pro"
planstring
Example: "pro"
statusstring | nullTRIALING, ACTIVE, PAST_DUE or CANCELED; null without a subscription.
Example: "ACTIVE"
trialEndsAtstring (date-time) | nullWhen the trial ends (status TRIALING).
Example: "2026-10-21T09:00:00Z"
upgradeUrlstringWhere to get more: the plans and their prices.
Example: "https://pricana.io/pricing"
usagePlanUsageThis month's use; null for an operator's token.

PlanUsage

Calls with API keys or tokens and exported rows this calendar month (UTC).

NameTypeDescription
apiCallsinteger
Example: 48211
exportRowsinteger
Example: 12000
resetsAtstring (date-time)When both start over (the first of next month, 00:00 UTC).
Example: "2026-11-01T00:00:00Z"

PriceRange

The lowest and highest price of a product's offers in one currency.

NameTypeDescription
currencystring
Example: "EUR"
maxnumber
Example: 1529
minnumber
Example: 1349
offersinteger
Example: 6

Product

A product across shops: the offers of the same product, matched by GTIN, else by brand and part number.

NameTypeDescription
brandstring | null
Example: "Lenovo"
categoryCategoryRefNull while it has none.
gtinstring | null
Example: "0196802123456"
idstringIts GTIN (digits), else its brand-MPN key.
Example: "0196802123456"
mpnstring | null
Example: "21KC004MGE"
offersintegerOffers (items) of it you can see.
Example: 6
pricesPriceRange[]The price range per currency.
shopsintegerDifferent websites selling it.
Example: 5
titlestring | null
Example: "Lenovo ThinkPad X1 Carbon Gen 12"

ProductDetail

A product with all its offers, cheapest first.

NameTypeDescription
offersItem[]
productProduct

SiteRef

The website an item comes from.

NameTypeDescription
attributionstring | nullThe source's licence and credit (open data, e.g. CC BY 4.0): pass it on with its data. Null for other sources.
Example: "Source: European Commission, Weekly Oil Bulletin, CC BY 4.0"
hoststring
Example: "www.notebookshop.example"
idinteger
Example: 4
namestring
Example: "Notebookshop"

Source

The source (one listing of one website) an item was read from.

NameTypeDescription
modelIdinteger
Example: 31
namestring
Example: "Notebookshop – Laptops"

WebhookEvent

What your webhook endpoint receives: the next changes of the change feed, in order, up to 100 at a time (type changes), or a test from the portal (type ping, no changes).

NameTypeDescription
changesChange[]
createdAtstring (date-time)
Example: "2026-10-07T09:12:31Z"
cursorinteger | nullThe id of the last change in it (null for a ping): /changes?after= goes on from it.
Example: 1811
idstringThe same on every attempt and when sent again: drop repeats by it.
Example: "evt_5f1c0b2a9d7e4c3b8a6f0e1d"
typestring, one of changes, ping
Example: "changes"