@torvion/rascador is the official, open-source TypeScript client for the Rascador API. It has no dependencies and runs on Node 18+, Bun, Deno, edge runtimes and in the browser.
npm install @torvion/rascadorbun add @torvion/rascadorpnpm add @torvion/rascadordeno add jsr:@torvion/rascadorCreate a key from API Keys and keep it in an environment variable. A rsc_test_ key is enough to start — see Environments for what it can and can't do.
import { Rascador } from "@torvion/rascador"
const rascador = new Rascador({ apiKey: process.env.RASCADOR_API_KEY })
const { data: me } = await rascador.me()
console.log(me.scopes)Every method returns the gateway's envelope unchanged as { data, meta }, with field names exactly as they appear in the API Reference.
| Method | Endpoint | Notes |
|---|---|---|
| me() | GET /v1/me | Scopes, limits and remaining quota. Free. |
| sources.list() | GET /v1/sources | Which sources exist and what each supports. Free. |
| categories.list({ q }) | GET /v1/categories | Served from cache. |
| products.list({ … }) | GET /v1/products | Filter stored products; iterate with for await. |
| products.get(id, { refresh }) | GET /v1/products/:id | Instant when stored; live-fetches otherwise. |
| search({ q, pages, refresh }) | GET /v1/search | Live search. Takes 20–40s. |
// Browse stored products by category
const { data: categories } = await rascador.categories.list({ q: "dress" })
const { data: products, meta } = await rascador.products.list({
category_id: categories[0].id,
on_sale: true,
limit: 20,
})
// Or walk every page
for await (const product of rascador.products.list({ brand: "SHEIN" })) {
console.log(product.title, product.price.current)
}
// Live search, then full details for a hit
const { data: hits } = await rascador.search({ q: "summer dress" })
const { data: product } = await rascador.products.get(String(hits[0].product_id))products.list accepts category_id, sku, q, brand, min_price, max_price, color, size, on_sale, limit and offset. Iterating it with for await follows meta.pagination.has_more for you.
Set a default source on the client and override it per call. sources.list() tells you which filters and live features each source supports.
const rascador = new Rascador({ apiKey, source: "shein" })
await rascador.search({ q: "usb-c hub", source: "amazon" })Any non-2xx response throws a RascadorErrorcarrying the gateway's error envelope. Branch on code, not on the message — the full list is on Errors & Limits.
import { RascadorError } from "@torvion/rascador"
try {
await rascador.search({ q: "linen shirt" })
} catch (err) {
if (!(err instanceof RascadorError)) throw err
switch (err.code) {
case "quota_exceeded":
console.log("Quota resets at", err.details?.resets_at)
break
case "insufficient_scope":
console.log("This key can't do that:", err.details)
break
default:
console.log(err.status, err.code, err.requestId)
}
}Each error has code, status, retryable, retryAfterSeconds, requestId and details. Include the requestId when you contact support.
search drives a real browser, so it gets a 130-second timeout by default; every other call gets 30 seconds. Errors the gateway marks retryable — rate limits and upstream outages — are retried up to twice, waiting at least as long as Retry-After asks. Quota spent on a failed call is refunded, so retries never double-charge.
const rascador = new Rascador({
apiKey,
timeoutMs: 60_000, // non-search calls
maxRetries: 0, // turn retries off
fetch: customFetch, // e.g. for proxies or tests
})
// Cancel a single call
const controller = new AbortController()
await rascador.search({ q: "desk lamp" }, { signal: controller.signal })The SDK is MIT-licensed and developed in the open on GitHub, published to npm and JSR. Issues and pull requests are welcome.