Skip to documentation content
HintadataDocs

Comparison and price history

Use a sandbox API key with catalog:read and compare:read, curl and jq. Search for at least two distinct products. Live requests require fresh source evidence and may consume usage credits.

In this guide
  1. 1Prerequisites
  2. 2Run and verify
  3. 3Recover safely
In this guide
  1. 1Prerequisites
  2. 2Run and verify
  3. 3Recover safely

Prerequisites and safety

Use a sandbox API key with catalog:read and compare:read, curl and jq. Search for at least two distinct products. Live requests require fresh source evidence and may consume usage credits.

Run the isolated exercise

Compare two products and read history
  1. 1
    Find product identities
  2. 2
    Compare delivered prices
  3. 3
    Read observed price history

Run from your server

bashillustrative
Example trust: illustrativeShows the shape or idea; do not use it unchanged in production.
set -euo pipefail
# Requires bash, curl and jq. Use an isolated sandbox API key.
DOCS_BASE_URL="${DOCS_BASE_URL:-https://hintadata.fi}"
: "${HINTADATA_API_KEY:?Set a sandbox API key privately}"
DOCS_VARIABLES=$(jq -cn  '{}')
DOCS_RESPONSE_FILE=$(mktemp)
trap 'rm -f -- "$DOCS_RESPONSE_FILE"' EXIT
# search: expected HTTP 200
DOCS_PATH="$(jq -cnr --argjson vars "$DOCS_VARIABLES" '"/v1/search?q=sony&limit=2"')"
DOCS_STATUS=$(curl --silent --show-error --max-time 20 --output "$DOCS_RESPONSE_FILE" --write-out '%{http_code}' -X 'GET' "$DOCS_BASE_URL$DOCS_PATH" -H "Authorization: Bearer $HINTADATA_API_KEY")
[[ "$DOCS_STATUS" == '200' ]] || { printf '%s\n' 'Unexpected HTTP status at search' >&2; exit 1; }
DOCS_RESPONSE=$(jq -c . "$DOCS_RESPONSE_FILE")
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("query") else false end))) and ($response["query"] == ("sony"))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("items") else false end) and ($response["items"] | if type == "object" or type == "array" then has(0) else false end) and ($response["items"][0] | if type == "object" or type == "array" then has("canonical_product_id") else false end)) == true)' >/dev/null
DOCS_VARIABLES=$(jq -cn --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" '$vars + {"productId":$response["items"][0]["canonical_product_id"],"secondId":$response["items"][1]["canonical_product_id"]}')
printf '%s\n' 'search: verified'
# compare: expected HTTP 200
jq -e 'has("productId")' <<< "$DOCS_VARIABLES" >/dev/null
jq -e 'has("secondId")' <<< "$DOCS_VARIABLES" >/dev/null
DOCS_PATH="$(jq -cnr --argjson vars "$DOCS_VARIABLES" '"/v1/compare?ids=" + ($vars["productId"] | tostring | @uri) + "," + ($vars["secondId"] | tostring | @uri) + ""')"
DOCS_STATUS=$(curl --silent --show-error --max-time 20 --output "$DOCS_RESPONSE_FILE" --write-out '%{http_code}' -X 'GET' "$DOCS_BASE_URL$DOCS_PATH" -H "Authorization: Bearer $HINTADATA_API_KEY")
[[ "$DOCS_STATUS" == '200' ]] || { printf '%s\n' 'Unexpected HTTP status at compare' >&2; exit 1; }
DOCS_RESPONSE=$(jq -c . "$DOCS_RESPONSE_FILE")
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("products") else false end) and ($response["products"] | if type == "object" or type == "array" then has(0) else false end) and ($response["products"][0] | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["products"][0]["canonical_product_id"] == ($vars["productId"]))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("products") else false end) and ($response["products"] | if type == "object" or type == "array" then has(1) else false end) and ($response["products"][1] | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["products"][1]["canonical_product_id"] == ($vars["secondId"]))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("products") else false end) and ($response["products"] | if type == "object" or type == "array" then has(0) else false end) and ($response["products"][0] | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["products"][0]["canonical_product_id"] == ($vars["productId"]))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("products") else false end) and ($response["products"] | if type == "object" or type == "array" then has(1) else false end) and ($response["products"][1] | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["products"][1]["canonical_product_id"] == ($vars["secondId"]))' >/dev/null
printf '%s\n' 'compare: verified'
# history: expected HTTP 200
jq -e 'has("productId")' <<< "$DOCS_VARIABLES" >/dev/null
DOCS_PATH="$(jq -cnr --argjson vars "$DOCS_VARIABLES" '"/v1/products/" + ($vars["productId"] | tostring | @uri) + "/history?range=30d"')"
DOCS_STATUS=$(curl --silent --show-error --max-time 20 --output "$DOCS_RESPONSE_FILE" --write-out '%{http_code}' -X 'GET' "$DOCS_BASE_URL$DOCS_PATH" -H "Authorization: Bearer $HINTADATA_API_KEY")
[[ "$DOCS_STATUS" == '200' ]] || { printf '%s\n' 'Unexpected HTTP status at history' >&2; exit 1; }
DOCS_RESPONSE=$(jq -c . "$DOCS_RESPONSE_FILE")
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["canonical_product_id"] == ($vars["productId"]))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("range") else false end))) and ($response["range"] == ("30d"))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("summary") else false end) and ($response["summary"] | if type == "object" or type == "array" then has("observation_count") else false end)) == true)' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("canonical_product_id") else false end))) and ($response["canonical_product_id"] == ($vars["productId"]))' >/dev/null
jq -en --argjson vars "$DOCS_VARIABLES" --argjson response "$DOCS_RESPONSE" --argjson status "$DOCS_STATUS" '((($response | if type == "object" or type == "array" then has("range") else false end))) and ($response["range"] == ("30d"))' >/dev/null
printf '%s\n' 'history: verified'

Verify the result

The comparison returns HTTP 200, products and each best_offer.delivered_price. History returns the same canonical_product_id, range, series and summary.observation_count. Zero observations mean no evidence for that interval, not zero price or a price forecast.

Recovery and cleanup

400: choose 2–4 distinct IDs; compare accepts no goal or range. Only history accepts these range values: 7d, 30d, 90d, 1y. 404: search again instead of guessing an ID. 503: verify source freshness. A null best_offer means no known available offer.

For 429 or temporary 5xx, respect Retry-After and use bounded retries. Keep API keys and response bodies out of logs and support tickets.

Was this page helpful?