API

Store-level stock, price and delivery ETA for Zepto, Blinkit, Swiggy Instamart and Flipkart Minutes. Base URL is this site. Create a key under API keys.

Basics

GET/api/v1/item?url=…&lat=…&lon=…

One product at one point, answered live. Waits up to wait seconds (default and max 25); if it isn't done by then you get 202 and a run_id to poll.

curl -H "Authorization: Bearer $QC_KEY" \
  "$BASE/api/v1/item?lat=12.9352&lon=77.6245&url=https://www.zepto.com/pn/x/pvid/aad60fd4-b197-4a5a-a407-70700a95a704"

{
  "run_id": 812, "platform": "zepto", "product": "Wellcore Creatine | 33 servings",
  "location": {"lat": 12.9352, "lon": 77.6245, "name": "12.9352, 77.6245"},
  "status": "IN_STOCK", "price_inr": 539, "mrp_inr": 699, "inventory": 4, "max_cart_qty": 6,
  "eta_minutes": 8, "fetched_at": "2026-09-28T14:45:02Z", "done": true, "charged": 1
}

POST/api/v1/runs

Up to 500 (product, point) pairs in one go. Returns 202 with an id; poll it.

curl -X POST -H "Authorization: Bearer $QC_KEY" -H "content-type: application/json" "$BASE/api/v1/runs" \
  -d '{"items":[{"url":"https://blinkit.com/prn/x/prid/707701","lat":28.7043,"lon":77.1217}]}'

{"id": 813, "status": "running", "poll": "/api/v1/runs/813"}

GET/api/v1/runs/{id}

status is running or done; items[] have the same fields as /item. charged is set once done.

POST/api/v1/watches

Keep a product fresh across every store in a city and get a webhook on every status change (Telegram gets restocks only). Costs 1 credit per store per refresh; the watch pauses when credits run out.

curl -X POST -H "Authorization: Bearer $QC_KEY" -H "content-type: application/json" "$BASE/api/v1/watches" \
  -d '{"url":"https://www.zepto.com/pn/x/pvid/…","city":"bangalore","every_s":300,
       "webhook_url":"https://example.com/hooks/stock"}'

{"id": 31, "webhook_secret": "whsec_…"}   # shown once

Billed per refresh interval, afterwards, only for stores that got a fresh answer; the watch pauses before an interval your balance couldn't cover.

GET /api/v1/watches lists them, DELETE /api/v1/watches/{id} removes one. every_s: 60, 300, 900 or 3600. Optional alert_on: restock (default) or change; max_price in paise alerts only at or below it.

POST/api/v1/schedules

A run that starts itself at set IST times and delivers its report. Each run is billed like a normal run; if your balance can't cover one, that run is skipped (and you're told), not partly run.

curl -X POST -H "Authorization: Bearer $QC_KEY" -H "content-type: application/json" "$BASE/api/v1/schedules" \
  -d '{"name":"morning sweep","urls":["https://www.zepto.com/pn/x/pvid/…"],"city":"bangalore",
       "hours":[9,18],"minute":0,"webhook_url":"https://example.com/hooks/report"}'

{"id": 4, "credits_per_run_max": 102, "webhook_secret": "whsec_…"}

Use points ([[lat,lon],…]) instead of city for specific spots. GET /api/v1/schedules lists, DELETE /api/v1/schedules/{id} removes. When a run finishes you get run.completed with every item (same fields as /runs/{id}, prices in paise).

WEBHOOKstock.changed

POST <your url>
x-qc-event: stock.changed
x-qc-signature: sha256=<hex HMAC-SHA256 of the raw body with your webhook_secret>

{"event":"stock.changed","platform":"zepto","listing":{"id":7,"name":"…","url":"…"},
 "store":{"id":2,"name":"BLR-Bommanahalli","serves":["Arekere","Hongasandra"]},
 "from":"OUT_OF_STOCK","to":"IN_STOCK","price":53900,"mrp":69900,"inventory":4,"at":1790600000}

Prices in webhooks are in paise. Verify before trusting:

import hmac, hashlib
ok = hmac.compare_digest(
    "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest(),
    request.headers["x-qc-signature"])

Failed deliveries retry with backoff (2, 4, 8… minutes) up to 6 attempts.

GET/api/v1/credits

{"balance": 9412}