API documentation
A single GET request returns a structured product record from a marketplace listing. No SDK required — it is HTTP and JSON.
Quickstart
Create an account, generate a key in the dashboard, and make your first call. New accounts include 250 free credits.
curl https://api.gravitrondata.com/v1/walmart/price \
-H "Authorization: Bearer gd_live_..." \
-G --data-urlencode "item_id=650209444"
Every response is JSON. A successful lookup costs one credit; the remaining
balance is returned on each response in X-Credits-Remaining.
Authentication
Pass your API key as a bearer token on every request.
Authorization: Bearer gd_live_xxxxxxxxxxxxxxxxxxxxxxxx
Keys are shown once at creation and stored only as a hash — we cannot recover one for you. If a key is lost or exposed, revoke it in the dashboard and generate a replacement. Revocation takes effect immediately.
You can hold up to 20 active keys. Issue one per environment or per service so a single compromised key can be revoked without disrupting everything else.
Credits & billing
Access is prepaid. One credit is consumed per lookup that returns an answer. Credits do not expire.
| Outcome | Charged | Why |
|---|---|---|
| Product data returned | 1 credit | A complete answer. |
| No product at that identifier | 1 credit | Still a real answer, and it required a live fetch. |
| Served from cache | 1 credit | You pay for the answer, not for our infrastructure. |
| Blocked, timed out, upstream failure | Free | Our failure. The credit is returned automatically. |
| Invalid key, bad parameters, rate limited | Free | No fetch was attempted. |
Check X-Credits-Charged on any response to see whether that
specific call cost you anything.
Endpoints
Base URL: https://api.gravitrondata.com
| Method | Path | Returns |
|---|---|---|
| GET | /v1/{marketplace}/product | Complete product record |
| GET | /v1/{marketplace}/price | Price, availability and seller only |
| GET | /health | Service status. No key required, not billed. |
{marketplace} is a slug from the API catalogue.
Marketplaces that are not yet available return 501 and are never
billed. /price returns a subset of /product — the same
underlying fetch, a smaller payload.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
item_id | string | One of the two | Marketplace item identifier. The format is the marketplace's own. |
url | string | One of the two | Full product URL. Useful when you have a link but not an ID. |
Supply exactly one. Supplying neither returns 400. When both are
given, url takes precedence.
| Marketplace | Identifier | Example |
|---|---|---|
walmart | Walmart item ID | 650209444 |
ebay | eBay item number | 285923847562 |
flipkart | Flipkart pid | MOBGTAGPTB3VS24W |
An identifier that does not match its marketplace's format returns
400 and is never billed. International sites are supported through
url: pass an ebay.co.uk or ebay.de listing
URL and it is fetched from that site, priced in that site's currency.
Response schema
The /product response for a live marketplace. Fields that a
listing does not carry are returned as null rather than omitted, so
you can rely on the shape being stable.
| Field | Type | Description |
|---|---|---|
marketplace | string | Slug of the marketplace the record came from. |
item_id | string | Marketplace identifier for the item. |
url | string | Canonical product URL. |
title | string | Listing title as displayed. |
brand | string | null | Brand name. |
model | string | null | Manufacturer model number. |
upc | string | null | UPC barcode where published. |
price.current | number | null | Price now, as a number. |
price.was | number | null | Struck-through price when discounted. |
price.unit | number | null | Price per unit of measure. |
price.unit_label | string | null | Human-readable unit price, e.g. $8.44/oz. |
price.currency | string | ISO currency code. |
price.is_reduced | boolean | True when a was-price is present. |
availability.in_stock | boolean | Whether the item is buyable now. |
availability.status | string | Raw status, e.g. IN_STOCK. |
availability.transactable_offers | integer | null | Offers that can actually be purchased. |
seller.name | string | null | Buy-box seller. |
seller.is_first_party | boolean | Sold by the marketplace itself, or by a third-party seller on it. |
seller.rating | number | null | Seller rating out of 5. |
reviews.rating | number | null | Average product rating. |
reviews.count | integer | null | Number of reviews. |
category_path | string | null | Breadcrumb category path. |
specifications | object | Name/value attribute pairs from the listing. |
images | array | Image URLs, primary first. |
Buy-box data is a point in time
On marketplaces with third-party sellers, the buy box rotates between
sellers with different prices and stock states. seller.name tells
you whose price you received. Two lookups minutes apart can legitimately
return different prices for the same item — that is the marketplace changing,
not an inconsistency in the data.
Marketplace-specific fields
The envelope above is shared, so code written against one marketplace parses
another. Where a marketplace publishes something the others do not, it is added
as its own field rather than being squeezed into one that means something else
elsewhere. Fields a marketplace does not publish are null.
| Field | Marketplace | Description |
|---|---|---|
auction.is_auction | eBay | False for ordinary Buy-It-Now listings. |
auction.bids | eBay | Bid count on an auction listing. |
auction.current_bid | eBay | Standing bid, in the listing's currency. |
auction.ends_at | eBay | Listing end instant, where eBay publishes one. |
seller.feedback_percent | eBay | Positive-feedback percentage. eBay publishes no star rating, so seller.rating is null there. |
availability.sold_quantity | eBay | Units already sold on the listing. |
fulfillment.item_location | eBay | Where the item ships from. |
fulfillment.ships_to | eBay | Destination the shipping quote assumes. eBay prices postage per destination, so the cost is only meaningful next to it. |
store.pickup_available | Home Depot | Whether the item can be collected from a branch. |
store.pickup_quantity | Home Depot | Units that branch is holding. |
store.pickup_store | Home Depot | Which branch the pickup figures describe. |
store.ship_to_home / delivery_available | Home Depot | Post and scheduled-delivery availability, which move independently of pickup. |
price.save_amount / save_percent | eBay, Home Depot, Flipkart | Saving in cash and percent against the was-price. |
store_sku | Home Depot | In-store SKU, distinct from the internet number. |
offers[] | Flipkart | Bank, exchange and no-cost-EMI offers. Not folded into price.current, because whether one applies depends on the buyer. |
seller.rating | Flipkart, Walmart | Seller rating out of 5. Null on eBay, which publishes a feedback percentage instead. |
reviews.review_count | Flipkart | Written reviews, which Flipkart counts separately from ratings given. |
listing_id | Flipkart | The itm… listing id, alongside the pid in item_id. |
price.unit / unit_label | Walmart | Price per unit of measure. |
seller.is_first_party | Walmart | Sold by the marketplace itself. Always false on eBay, where every listing is a seller's own. |
ingredients, directions | Walmart | Grocery and drug listings only. |
Response headers
| Header | Description |
|---|---|
X-Credits-Remaining | Balance after this request. |
X-Credits-Charged | 1 if billed, 0 if not. |
Errors & retries
Errors return a JSON body with an error field.
| Status | Meaning | Charged | What to do |
|---|---|---|---|
200 | Success | Yes | — |
400 | Missing or invalid parameters | No | Send item_id or url. |
401 | Missing, malformed, invalid or revoked key | No | Check the Authorization header. |
402 | Out of credits | No | Top up in the dashboard. |
404 | No product at that identifier | Yes | Do not retry — the answer will not change. |
429 | Rate limit exceeded | No | Back off and retry. |
501 | Marketplace not yet available | No | Do not retry. |
502 / 503 | Lookup failed on our side | No | Retry once after a short delay. |
Build one retry into your client
These are live fetches of real marketplace pages behind commercial bot
protection. Roughly 1 in 20 uncached lookups fails and returns
502. You are never charged for those, and a single retry almost
always succeeds. We would rather state this plainly than have you discover it
in production.
Rate limits
Limits are per account, set by the largest bundle you have purchased.
Exceeding one returns 429 and costs nothing.
| Plan | Requests / minute |
|---|---|
| Free trial | 3 |
| Starter | 8 |
| Growth | 20 |
| Scale | 120 |
Limits reflect real capacity rather than an arbitrary tier ladder. Every request is a live fetch of a marketplace page, so throughput — not storage — is the scarce resource. If you need sustained volume beyond the Scale tier, get in touch before building against it.
Caching & freshness
Responses are cached for five minutes per item. A cached response is returned in milliseconds instead of seconds, and still costs one credit.
If you are making pricing decisions on fast-moving items, treat any response as up to five minutes old. Marketplace prices and buy-box winners change continuously; a response describes a moment, not a steady state.
Code samples
Python
import requests, time
API = "https://api.gravitrondata.com/v1/walmart/price"
KEY = "gd_live_..."
def lookup(item_id, attempts=2):
for i in range(attempts):
r = requests.get(API, params={"item_id": item_id},
headers={"Authorization": f"Bearer {KEY}"}, timeout=90)
if r.status_code < 500:
r.raise_for_status()
return r.json()
time.sleep(1.5) # our failure, not yours — never billed
r.raise_for_status()
data = lookup("650209444")
print(data["price"]["current"], data["seller"]["name"])
Node.js
const API = "https://api.gravitrondata.com/v1/walmart/price";
const KEY = "gd_live_...";
async function lookup(itemId, attempts = 2) {
for (let i = 0; i < attempts; i++) {
const r = await fetch(`${API}?item_id=${encodeURIComponent(itemId)}`, {
headers: { Authorization: `Bearer ${KEY}` },
});
if (r.status < 500) {
if (!r.ok) throw new Error(`${r.status} ${await r.text()}`);
return r.json();
}
await new Promise(res => setTimeout(res, 1500));
}
throw new Error("upstream unavailable");
}
PHP
<?php
$key = 'gd_live_...';
$url = 'https://api.gravitrondata.com/v1/walmart/price?item_id=650209444';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
CURLOPT_TIMEOUT => 90,
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($body, true);
echo $data['price']['current'];
Shell
# Full record
curl -s https://api.gravitrondata.com/v1/walmart/product \
-H "Authorization: Bearer gd_live_..." \
-G --data-urlencode "item_id=650209444" | jq .
# By URL instead of ID
curl -s https://api.gravitrondata.com/v1/walmart/price \
-H "Authorization: Bearer gd_live_..." \
-G --data-urlencode "url=https://www.walmart.com/ip/650209444"
Changelog
- 2026-08-12
- Flipkart is live:
/v1/flipkart/productand/v1/flipkart/price. Adds theofferslist — bank, exchange and no-cost-EMI offers, which move what a buyer actually pays — plus a real out-of-5seller.ratingandreviews.review_countseparate from ratings given. All prices in INR; identifiers are the Flipkartpid. - 2026-08-12
- Home Depot is live:
/v1/homedepot/productand/v1/homedepot/price. Adds thestoreblock — pickup availability, the quantity a branch holds, and which branch that is — plusprice.save_amount,price.save_percentandstore_sku. Online stock and branch stock are reported separately because they move independently. - 2026-08-12
- eBay is live:
/v1/ebay/productand/v1/ebay/price. Adds theauctionblock,seller.feedback_percent,availability.sold_quantityandfulfillment.item_location. International eBay sites are supported by passing a listingurl. Credits are shared across marketplaces — nothing to buy again. - 2026-08-12
- Public launch. First marketplace endpoints (
/product,/price), prepaid credits, per-account rate limits.
Something unclear or missing? Documentation gaps are bugs — tell us and we will fix them.