A smart JSON API (plus a browsable UI) for clearance deals and live per-store stock, proxying hiddenclearances.com. Built to be dropped straight into a Discord bot — there's even a Discord-embed-ready endpoint.
Base URL: https://rfh6au2--019e7c910d087570a7d215d88e70638c.web.val.run
The upstream API needs a Supabase JWT Bearer token that expires (~1 hour). Grab the
authorization: header value from a logged-in request on hiddenclearances.com and save it.
👉 Add HC_TOKEN here: https://www.val.town/x/rfh6au2/clearance-api/environment-variables?key=HC_TOKEN
Check GET /api/health — when tokenConfigured is true and stock calls return data,
you're good. If calls start returning token_expired, refresh the token at the link above.
Every endpoint returns a consistent shape, so error handling in your bot is trivial:
{ "ok": true, /* ...payload... */ } { "ok": false, "error": { "code": "token_expired", "message": "..." } }
Common error codes: missing_params, missing_query, missing_zip, missing_token,
token_expired, upstream_error, not_found, internal_error.
| Route | Description |
|---|---|
GET /api/health | Service + token status, supported retailers. No auth/params. |
GET /api/retailers | Supported retailer slugs and their accepted aliases. |
GET /api/leads?limit=24&page=1&sort=newest&retailer= | Paginated deals feed. sort = newest/oldest/discount/price. |
GET /api/leads/search?q=dewalt&pages=3&limit=24 | Keyword search across the first N feed pages. |
GET /api/stock?retailer=home_depot&sku=336764660&zip=80019 | Per-store stock + a smart summary + raw stores. |
GET /api/deal/:retailer/:sku?zip=80019 | Path-style stock lookup (same payload as /api/stock). |
GET /api/discord/stock?retailer=home_depot&sku=336764660&zip=80019 | Discord-embed-ready { content, embeds } you can post directly. |
retailer accepts home_depot / homedepot / hd, lowes / lowe's, walmart / wm.
{ "ok": true, "retailer": "homedepot", "sku": "336764660", "zip": "80019", "item": { /* upstream item info, incl. retailPrice */ }, "summary": { "storesChecked": 32, "inStockCount": 4, "totalQuantity": 11, "nearest": { "storeName": "...", "distanceMiles": 6.2, "quantity": 3, "price": 4.99, "itemLocation": "Aisle 12, Bay 4" } }, "inStockStores": [ /* only stores with stock, nearest first */ ], "stores": [ /* full raw list, every store */ ] }
The /api/discord/stock route already returns a valid Discord message payload, so a
slash command is basically a passthrough:
// /stock <sku> <zip> [retailer]
const API = "https://rfh6au2--019e7c910d087570a7d215d88e70638c.web.val.run";
async function handleStock(sku: string, zip: string, retailer = "home_depot") {
const r = await fetch(`${API}/api/discord/stock?retailer=${retailer}&sku=${sku}&zip=${zip}`);
const data = await r.json();
if (!data.ok) {
return { content: `❌ ${data.error.message}` };
}
return { content: data.content, embeds: data.embeds }; // post straight to Discord
}
For a custom layout, hit /api/stock instead and build your own embed from summary
and inStockStores.
Visit / for a browsable grid of deals with a "Check stock" modal. The frontend calls
the same /api/* endpoints.
Rendering mermaid diagram...