Developers
Profitr Catalogue API
UK resale market prices for bots, cash-out servers and tools. The true market price, 30-day sold market, live market and trend, plus a plain-English summary for every item in the Profitr catalogue.
Getting started
- Sign in to Profitr and open Settings → API. Request access and tell us how you’ll use it.
- Once approved, generate your key. You get 50 free calls to try it.
- Pick a plan when you’re ready. Usage, billing and your overage cap live on the same page.
Send your key on every request as Authorization: Bearer pk_live_…. The API is server-to-server only: keep the key in a secret store (e.g. a Supabase secret), never in browser code. Base URL: https://api.profitr.co.uk/v1.
// Supabase edge function (Deno): price a member's cash-out submission
const API = "https://api.profitr.co.uk/v1";
const headers = {
Authorization: `Bearer ${Deno.env.get("PROFITR_API_KEY")}`,
"Content-Type": "application/json",
};
// 1. Find the item once and store its id
const search = await fetch(`${API}/items/search?q=${encodeURIComponent("ascended heroes bundle case")}`, { headers });
const [item] = (await search.json()).data;
// 2. Price many stored ids in one call (1 call per item returned)
const res = await fetch(`${API}/items/batch`, { method: "POST", headers, body: JSON.stringify({ ids: [item.id] }) });
if (res.status === 429) await new Promise((r) => setTimeout(r, Number(res.headers.get("Retry-After") ?? 5) * 1000));
const { data } = await res.json();
const offer = data[0].market.true_market_gbp * 0.8; // your cash-out ratePricing
Starter
£19/mo
1,000 calls
then £0.02375/call · 60 req/min
Growth
£49/mo
10,000 calls
then £0.006125/call · 300 req/min
Scale
£99/mo
50,000 calls
then £0.002475/call · 600 req/min
50,000+
Enquire
Custom allowance
GBP, billed monthly, no VAT. Overage is 125% of your plan’s per-call rate, with a default safety cap of 2× your allowance (adjustable). Trial keys are limited to 20 requests/min.
How prices work
- Sold market: the latest 10 UK eBay sales within 30 days (highest and lowest trimmed when there are 5+), median, item price ex postage. Falls back to 90 days when sales are thin.
momentum_pctcompares it with sales 31–90 days ago. - Live market: the cheapest 10 UK fixed-price listings from sellers with more than 10 feedback and 100% positive, median. The lowest two only count if they’re within 20% of the rest.
- True market: the average of sold and live when they’re within ±5% (
trend: flat); otherwise the sold market, withtrendup or down by where live sits. - Freshness: figures older than 48 hours refresh in the background when you request an item (
refreshing: true). Addrefresh=wait(item) or"refresh": "wait"(batch) to refresh them before the response instead. Search returns stored figures only. - summary is display-only English text. Build logic on the structured fields; wording can change with
market.method.
Endpoints
get/items/search
Search items by name
Stored figures only — search never triggers a refresh. 1 call. Max 25 results.
q(query, required) — stringlimit(query) — integer, max 25
get/items
Look up items by TCGplayer id
1 call.
tcgplayer_id(query, required) — string
get/items/{id}
Get one item
Figures older than 48 hours refresh in the background (`refreshing: true`); call again later for the newer figure. With `refresh=wait`, a figure older than 48 hours is refreshed before the response (can take ~5–20s). 1 call.
id(path, required) — stringrefresh(query) — string
post/items/batch
Get many items
Up to 100 ids. Charged 1 call per item returned (minimum 1). Unknown ids are listed in `not_found` and not charged. Send `"refresh": "wait"` to refresh up to 25 figures older than 48h before the response (allow up to ~50s); any not finished come back with `refreshing: true`.
get/items/{id}/history
Daily price history
Full history. 1 call.
id(path, required) — stringfrom(query) — stringto(query) — string
get/usage
Your plan and usage
Free — not counted.
post/requests
Request a new catalogue item
Joins the Profitr review queue. Free, max 5 per day.
Batch accepts up to 100 ids and is charged per item returned. Every response has meta with your usage, plus X-RateLimit-* and X-Request-Id headers.
Example item
{
"data": {
"id": "6f1c…",
"title": "Ascended Heroes Booster Bundle Case",
"category": "Sealed TCG",
"rrp_gbp": 179.99,
"tcgplayer_id": "593355",
"market": {
"true_market_gbp": 214.5,
"basis": "blend",
"trend": "flat",
"spread_pct": 3.1,
"method": "profitr_market_v1",
"updated_at": "2026-10-25T09:12:00Z",
"sources": [
{ "type": "sold", "value_gbp": 211.2, "count": 10, "window_days": 30, "confidence": "ok",
"prior_gbp": 198.0, "momentum_pct": 6.67, "lowest_gbp": 189.99 },
{ "type": "live", "value_gbp": 217.8, "check_gbp": 229.0, "count": 25, "confidence": "ok",
"lowest_gbp": 205.0, "low_outlier_gbp": [], "seller_excluded_count": 3 }
]
},
"summary": {
"sold": "Current 30d market is £211.20 based on 10 sales. …",
"live": "Current active market is £217.80 based on 25 qualifying listings. …",
"seller_exclusions": "3 listings were excluded because the seller had 10 or fewer feedback or was under 100% positive."
},
"links": { "market_page": "https://app.profitr.co.uk/market/6f1c…" },
"refreshing": false
},
"meta": { "request_id": "req_…", "plan": "growth", "calls_used": 4211, "calls_included": 10000, "overage_calls": 0 }
}Errors
Errors return { "error": { "code", "message" } }.
| Code | HTTP | Meaning |
|---|---|---|
| invalid_key | 401 | Missing or wrong key. |
| trial_exhausted | 402 | All 50 free calls used — subscribe to a plan. |
| insufficient_calls | 402 | Not enough free calls left for this batch. |
| no_plan | 402 | No active plan. |
| cap_reached | 402 | Your overage safety cap for this period is reached. |
| suspended | 403 | Account suspended. |
| not_found | 404 | Item not found (or not approved). |
| invalid_request | 422 | Bad parameters or body. |
| rate_limited | 429 | Too many requests this minute — wait for Retry-After seconds. |