Guides
Price check for one SKU
Find the cheapest confirmed competitor for one SKU and compare it with your own price. The example skips stale prices and unconfirmed matches.
import os
from decimal import Decimal
import requests
BASE = "https://api.getprice.ai/v1"
KEY = os.environ["GETPRICE_API_KEY"]
SKU = "10072L"
resp = requests.get(
f"{BASE}/comparison-sets",
params=[("sku", SKU)],
headers={"Authorization": f"Bearer {KEY}"},
timeout=30,
)
resp.raise_for_status()
page = resp.json()
status = page["skus"][0]["status"]
if status != "found": # no_comparison_set, unknown_sku
raise SystemExit(f"{SKU}: {status}")
for cset in page["data"]:
offers = [
e
for e in cset["competitors"]
if e["price"]
and not e["stale"]
and e["match"]["review"] == "same"
]
if not offers:
print(f"{SKU}: no fresh competitor prices")
continue
best = min(
offers,
key=lambda e: Decimal(e["price"]["amount"]),
)
low = Decimal(best["price"]["amount"])
name = best["competitor"]["name"]
print(f"{SKU}: cheapest is {name} at R{low}")
if best["price"]["was"]:
was = Decimal(best["price"]["was"])
off = was - low
print(f"On promotion: was R{was}, R{off} off.")
own = cset["own_product"]
if own and own["price"]:
mine = Decimal(own["price"]["amount"])
diff = mine - low
print(f"You charge R{mine}, R{diff} more.")interface Entry {
competitor: { name: string };
price: { amount: string; was: string | null } | null;
stale: boolean;
match: { review: string };
}
interface CompSet {
own_product: {
price: { amount: string } | null;
} | null;
competitors: Entry[];
}
interface Page {
data: CompSet[];
skus: { status: string }[];
}
const BASE = "https://api.getprice.ai/v1";
const KEY = process.env.GETPRICE_API_KEY;
const SKU = "10072L";
// Amounts have two decimals: work in cents.
const cents = (a: string) => Number(a.replace(".", ""));
const rands = (c: number) =>
`R${Math.floor(c / 100)}.` +
String(c % 100).padStart(2, "0");
const params = new URLSearchParams({ sku: SKU });
const url = `${BASE}/comparison-sets?${params}`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${KEY}` },
});
if (!res.ok) {
throw new Error(`GetPrice returned ${res.status}`);
}
const page = (await res.json()) as Page;
const { status } = page.skus[0];
if (status !== "found") {
throw new Error(`${SKU}: ${status}`);
}
for (const set of page.data) {
const offers = set.competitors.filter(
(e) =>
e.price && !e.stale && e.match.review === "same",
);
if (offers.length === 0) {
console.log(`${SKU}: no fresh competitor prices`);
continue;
}
const price = (e: Entry) => cents(e.price!.amount);
const best = offers.reduce((a, b) =>
price(b) < price(a) ? b : a,
);
const low = price(best);
const name = best.competitor.name;
console.log(
`${SKU}: cheapest is ${name} at ${rands(low)}`,
);
const was = best.price!.was;
if (was) {
const off = cents(was) - low;
console.log(
`On promotion: was ${rands(cents(was))}, ` +
`${rands(off)} off.`,
);
}
const own = set.own_product?.price;
if (own) {
const mine = cents(own.amount);
console.log(
`You charge ${rands(mine)}, ` +
`${rands(mine - low)} more.`,
);
}
}<?php
const SKU = "10072L";
$base = "https://api.getprice.ai/v1";
$key = getenv("GETPRICE_API_KEY");
// Amounts have two decimals: work in cents.
$cents = fn (string $a): int =>
(int) str_replace(".", "", $a);
$rands = fn (int $c): string =>
sprintf("R%d.%02d", intdiv($c, 100), $c % 100);
$sku = rawurlencode(SKU);
$ch = curl_init("$base/comparison-sets?sku=$sku");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $key",
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($body === false || $status >= 400) {
throw new RuntimeException(
"GetPrice returned $status: $body"
);
}
$data = json_decode(
$body, true, flags: JSON_THROW_ON_ERROR
);
$skuStatus = $data["skus"][0]["status"];
if ($skuStatus !== "found") {
throw new RuntimeException(SKU . ": $skuStatus");
}
foreach ($data["data"] as $set) {
$offers = array_values(array_filter(
$set["competitors"],
fn ($e) => $e["price"] && !$e["stale"]
&& $e["match"]["review"] === "same",
));
if (!$offers) {
echo SKU, ": no fresh competitor prices\n";
continue;
}
$price = fn ($e) => $cents($e["price"]["amount"]);
usort(
$offers,
fn ($a, $b) => $price($a) <=> $price($b),
);
$best = $offers[0];
$low = $price($best);
printf(
"%s: cheapest is %s at %s\n",
SKU,
$best["competitor"]["name"],
$rands($low),
);
$was = $best["price"]["was"];
if ($was !== null) {
printf(
"On promotion: was %s, %s off.\n",
$rands($cents($was)),
$rands($cents($was) - $low),
);
}
$own = $set["own_product"]["price"] ?? null;
if ($own) {
$mine = $cents($own["amount"]);
printf(
"You charge %s, %s more.\n",
$rands($mine),
$rands($mine - $low),
);
}
}using System.Globalization;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Naming = System.Text.Json.JsonNamingPolicy;
var key = Environment.GetEnvironmentVariable(
"GETPRICE_API_KEY");
var api = new Uri("https://api.getprice.ai/v1/");
var http = new HttpClient { BaseAddress = api };
http.Timeout = TimeSpan.FromSeconds(30);
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", key);
var json = new JsonSerializerOptions
{
PropertyNamingPolicy = Naming.SnakeCaseLower,
};
const string Sku = "10072L";
// Amounts are decimal strings: parse as decimal.
var inv = CultureInfo.InvariantCulture;
decimal Amount(Price p) => decimal.Parse(p.Amount, inv);
string Rands(decimal r) =>
"R" + r.ToString("0.00", inv);
var res = await http.GetAsync(
$"comparison-sets?sku={Sku}");
res.EnsureSuccessStatusCode();
var page = await res.Content
.ReadFromJsonAsync<Page>(json);
var status = page!.Skus[0].Status;
if (status != "found")
throw new Exception($"{Sku}: {status}");
foreach (var set in page.Data)
{
var offers = set.Competitors
.Where(e => e.Price is not null && !e.Stale)
.Where(e => e.Match.Review == "same")
.ToList();
if (offers.Count == 0)
{
Console.WriteLine($"{Sku}: no fresh prices");
continue;
}
var best = offers.MinBy(e => Amount(e.Price!))!;
var low = Amount(best.Price!);
var name = best.Competitor.Name;
Console.WriteLine(
$"{Sku}: cheapest is {name} at {Rands(low)}");
if (best.Price!.Was is { } wasText)
{
var was = decimal.Parse(wasText, inv);
Console.WriteLine(
$"On promotion: was {Rands(was)}, "
+ $"{Rands(was - low)} off.");
}
if (set.OwnProduct?.Price is { } own)
{
var mine = Amount(own);
Console.WriteLine(
$"You charge {Rands(mine)}, "
+ $"{Rands(mine - low)} more.");
}
}
record Page(List<CompSet> Data, List<SkuStatus> Skus);
record SkuStatus(string Status);
record CompSet(
OwnProduct? OwnProduct,
List<Entry> Competitors);
record OwnProduct(Price? Price);
record Entry(
Competitor Competitor,
Price? Price,
bool Stale,
Match Match);
record Competitor(string Name);
record Match(string Review);
record Price(string Amount, string? Was);Output
10072L: cheapest is Harbour Market at R17.99
On promotion: was R19.99, R2.00 off.
You charge R18.99, R1.00 more.To check many SKUs, send up to 100 sku values per request, and read skus to see which codes were found.