Skip to documentation content
HintadataDocs

Partial batch resolution

Use an isolated sandbox key with catalog:read, bash, curl and jq. Each batch accepts 1–100 inputs. Resolve a known product and a deliberately missing canonical ID, then read both offer results. Production batches consume one comparison credit per input, including unmatched inputs.

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 an isolated sandbox key with catalog:read, bash, curl and jq. Each batch accepts 1–100 inputs. Resolve a known product and a deliberately missing canonical ID, then read both offer results. Production batches consume one comparison credit per input, including unmatched inputs.

Run the isolated exercise

Resolve a partial batch without inventing offers
  1. 1
    Find product identities
  2. 2
    Resolve known and missing identities
  3. 3
    Preserve partial results and missing evidence

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'
# resolve: expected HTTP 200
jq -e 'has("productId")' <<< "$DOCS_VARIABLES" >/dev/null
DOCS_PATH="$(jq -cnr --argjson vars "$DOCS_VARIABLES" '"/v1/products/resolve"')"
DOCS_STATUS=$(curl --silent --show-error --max-time 20 --output "$DOCS_RESPONSE_FILE" --write-out '%{http_code}' -X 'POST' "$DOCS_BASE_URL$DOCS_PATH" -H "Authorization: Bearer $HINTADATA_API_KEY" -H 'Content-Type: application/json' --data "$(jq -cnr --argjson vars "$DOCS_VARIABLES" '{"items":[{"canonical_product_id":$vars["productId"]},{"canonical_product_id":"docs-missing-product"}]}')")
[[ "$DOCS_STATUS" == '200' ]] || { printf '%s\n' 'Unexpected HTTP status at resolve' >&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("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("status") else false end))) and ($response["items"][0]["status"] == ("matched"))' >/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("candidates") else false end) and ($response["items"][0]["candidates"] | if type == "object" or type == "array" then has(0) else false end))) and ($response["items"][0]["candidates"][0] == ($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("items") else false end) and ($response["items"] | if type == "object" or type == "array" then has(1) else false end) and ($response["items"][1] | if type == "object" or type == "array" then has("status") else false end))) and ($response["items"][1]["status"] == ("unmatched"))' >/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(1) else false end) and ($response["items"][1] | if type == "object" or type == "array" then has("candidates") else false end))) and ($response["items"][1]["candidates"] == ([]))' >/dev/null
printf '%s\n' 'resolve: verified'
# offers: expected HTTP 200
jq -e 'has("productId")' <<< "$DOCS_VARIABLES" >/dev/null
DOCS_PATH="$(jq -cnr --argjson vars "$DOCS_VARIABLES" '"/v1/offers/batch"')"
DOCS_STATUS=$(curl --silent --show-error --max-time 20 --output "$DOCS_RESPONSE_FILE" --write-out '%{http_code}' -X 'POST' "$DOCS_BASE_URL$DOCS_PATH" -H "Authorization: Bearer $HINTADATA_API_KEY" -H 'Content-Type: application/json' --data "$(jq -cnr --argjson vars "$DOCS_VARIABLES" '{"items":[{"canonical_product_id":$vars["productId"]},{"canonical_product_id":"docs-missing-product"}]}')")
[[ "$DOCS_STATUS" == '200' ]] || { printf '%s\n' 'Unexpected HTTP status at offers' >&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("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("status") else false end))) and ($response["items"][0]["status"] == ("matched"))' >/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(1) else false end) and ($response["items"][1] | if type == "object" or type == "array" then has("status") else false end))) and ($response["items"][1]["status"] == ("unmatched"))' >/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(1) else false end) and ($response["items"][1] | if type == "object" or type == "array" then has("offers") else false end))) and ($response["items"][1]["offers"] == ([]))' >/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(1) else false end) and ($response["items"][1] | if type == "object" or type == "array" then has("best_offer") else false end))) and ($response["items"][1]["best_offer"] == (null))' >/dev/null
printf '%s\n' 'offers: verified'

Verify the result

Both batches return HTTP 200, but only the first row is matched. Input order is preserved. The missing row has no candidates or offers and best_offer is null: that is missing evidence, not a zero price or proof of sold-out stock. The commands verify these values explicitly.

Recovery and cleanup

Handle every row status independently. For unmatched, fix the identifier; for ambiguous, review the candidates and select an exact canonical ID. An invalid GTIN or multiple identifiers in one row rejects the request. For 503 source_stale, wait for the source owner to refresh evidence; do not convert it into an empty successful result. These read-only POSTs need no Idempotency-Key.

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?