Public
Remixed
Hidden Clearances browser — deals feed + per-store stock lookup
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

🏷️ Clearance API

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

⚠️ First: set your token (required)

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.

Response envelope

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.

Endpoints

RouteDescription
GET /api/healthService + token status, supported retailers. No auth/params.
GET /api/retailersSupported 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=24Keyword search across the first N feed pages.
GET /api/stock?retailer=home_depot&sku=336764660&zip=80019Per-store stock + a smart summary + raw stores.
GET /api/deal/:retailer/:sku?zip=80019Path-style stock lookup (same payload as /api/stock).
GET /api/discord/stock?retailer=home_depot&sku=336764660&zip=80019Discord-embed-ready { content, embeds } you can post directly.

retailer accepts home_depot / homedepot / hd, lowes / lowe's, walmart / wm.

/api/stock payload

{ "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 */ ] }

Using it from a Discord bot

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.

UI

Visit / for a browsable grid of deals with a "Check stock" modal. The frontend calls the same /api/* endpoints.

Structure

Rendering mermaid diagram...