Qualit.ly API
Product data, QC images and metadata from Weidian, Taobao and 1688. Bearer token auth, generous rate limits, tiered plans.
Getting Started
All requests go to https://backend.qualit.ly/api/v1. Three steps:
- 1
Get a key
Sign in and create an API key from the developer dashboard.
- 2
Make a request
Send your key as a Bearer token in the Authorization header.
- 3
Get data
Receive JSON responses with product data and QC images.
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/products/weidian/7231368393Authentication
Include a valid API key in the Authorization header using the Bearer scheme.
Authorization: Bearer qc_live_xxxxxxxxxxxxxxxxxxxxxxxxKey format
Keys follow qc_{mode}_{random}, where mode is live or test and random is 32 cryptographically random characters.
Keys are shown once at creation. We store only the SHA-256 hash, so lost keys cannot be recovered — revoke and mint a new one.
IP allowlisting
Optionally restrict keys to specific IPs or CIDR ranges from the developer dashboard. Requests from unlisted IPs get a 403. An empty allowlist allows all IPs.
Rate Limits
Two buckets: per-minute and per-month. Your tier is read from your account on every request — upgrades take effect immediately — and the limits apply across all of your keys.
/me and /usage authenticate but are not metered: asking where you stand doesn't spend the quota you're asking about.
Headers
Sent on every response, not just the rejections.
When rate limited
The API returns 429 — RATE_LIMITED for the per-minute burst, QUOTA_EXCEEDED for the monthly quota — with the seconds to wait in retry_after.
{
"error": {
"code": "RATE_LIMITED",
"message": "Per-minute rate limit exceeded",
"retry_after": 37
}
}Errors
Errors return a non-2xx status and a top-level error object with a stable code and a message. Match on the code, not the message — messages may change.
{
"error": {
"code": "NOT_FOUND",
"message": "Product not found"
}
}Endpoints
Paths below are relative to https://backend.qualit.ly/api/v1. Storefronts are weidian, taobao and 1688. Endpoints without a chip work on every plan.
Get Product
/products/{storefront}/{listing_id}A single listing by storefront and ID. Returns its metadata and up to 5 QC preview thumbnails. This is the endpoint most integrations start with.
Example
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/products/weidian/7231368393Response
{
"data": {
"id": 482910,
"storefront": "weidian",
"listing_id": "7231368393",
"name": "AJ1 Retro High OG",
"price": "¥470.00",
"pic_url": "https://cdn.qualit.ly/covers/62743f38.jpg",
"pic_gif": null,
"product_url": "https://weidian.com/item.html?itemID=7231368393",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"qc_preview": [
"https://cdn.qualit.ly/qc/91c614ef.jpg",
"https://cdn.qualit.ly/qc/b66b2442.jpg"
]
}
}Search Products
/products/searchSearch the catalogue by product name — the product URL is matched too. There is no pagination: each plan returns up to a fixed number of results.
No pagination. Each plan returns up to a fixed number of results per search; limit can ask for fewer, never more.
Example
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
"https://backend.qualit.ly/api/v1/products/search?q=jordan+1&storefront=weidian&has_qc=true&limit=10"Response
{
"query": "jordan 1",
"count": 10,
"limit": 10,
"max_results": 100,
"data": [
{
"id": 482910,
"storefront": "weidian",
"listing_id": "7231368393",
"name": "AJ1 Retro High OG",
"price": "¥470.00",
"pic_url": "https://cdn.qualit.ly/covers/62743f38.jpg",
"product_url": "https://weidian.com/item.html?itemID=7231368393",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"qc_preview": ["https://cdn.qualit.ly/qc/91c614ef.jpg"]
}
]
}Fields
Batch Products
Pro+/products/batchResolve up to 100 listings in one call. Each item resolves independently, so a missing product doesn't fail the batch — it comes back as an error entry in the same position.
Request body
{
"items": [
{ "storefront": "weidian", "listing_id": "7231368393" },
{ "storefront": "taobao", "listing_id": "123456789" }
]
}Example
curl -X POST \
-H "Authorization: Bearer qc_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"items":[{"storefront":"weidian","listing_id":"7231368393"}]}' \
https://backend.qualit.ly/api/v1/products/batchResponse
{
"results": [
{
"data": {
"id": 482910,
"storefront": "weidian",
"listing_id": "7231368393",
"name": "AJ1 Retro High OG",
"price": "¥470.00",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"qc_preview": ["https://cdn.qualit.ly/qc/91c614ef.jpg"]
}
},
{ "error": { "code": "NOT_FOUND" } }
]
}Random Product
/products/randomOne random listing that has QC photos — for showcases, feeds, or sampling the catalogue. No body needed.
Example
curl -X POST \
-H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/products/randomResponse
{
"data": {
"id": 482910,
"storefront": "weidian",
"listing_id": "7231368393",
"name": "AJ1 Retro High OG",
"price": "¥470.00",
"pic_url": "https://cdn.qualit.ly/covers/62743f38.jpg",
"product_url": "https://weidian.com/item.html?itemID=7231368393",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"qc_preview": ["https://cdn.qualit.ly/qc/91c614ef.jpg"]
}
}QC Metadata
/qc/{storefront}/{listing_id}The QC photo count for a listing, plus the first three thumbnails — without pulling the full image list.
Example
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/qc/weidian/7231368393Response
{
"data": {
"storefront": "weidian",
"listing_id": "7231368393",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"thumbnails": [
"https://cdn.qualit.ly/qc/91c614ef.jpg",
"https://cdn.qualit.ly/qc/b66b2442.jpg",
"https://cdn.qualit.ly/qc/0f19ab77.jpg"
]
}
}QC Images
Pro+/qc/{id}/imagesEvery indexed QC photo for a listing. Takes the numeric product ID, or pass ?url= with any supported product link and let the API resolve it.
By product ID
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/qc/482910/imagesBy URL
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
"https://backend.qualit.ly/api/v1/qc/0/images?url=https://weidian.com/item.html?itemID=7231368393"Response
{
"data": {
"id": 482910,
"storefront": "weidian",
"listing_id": "7231368393",
"qualitly_url": "https://qualit.ly/weidian/7231368393?utm_source=api&utm_content=key_7",
"qc_count": 12,
"images": [
"https://cdn.qualit.ly/qc/91c614ef.jpg",
"https://cdn.qualit.ly/qc/b66b2442.jpg"
]
}
}The ?url= parameter accepts product links from Weidian, Taobao and 1688, and from every agent the link converter supports. Images are always CDN URLs.
Account Info
/meYour account, the key that made the request and the tier it resolves to. Useful as a health check.
Example
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/meResponse
{
"user": { "id": 12345, "username": "you" },
"key": { "id": 7, "mode": "live" },
"tier": "pro_plus"
}Usage
/usageWhere you stand in both rate-limit buckets, with reset timestamps. Like /me, this endpoint authenticates but is not metered — asking about your quota does not spend it.
Example
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
https://backend.qualit.ly/api/v1/usageResponse
{
"tier": "pro_plus",
"key": { "id": 7, "mode": "live" },
"minute": {
"limit": 1000,
"used": 12,
"remaining": 988,
"reset_in_seconds": 37,
"reset_at": "2026-08-20T18:42:00.000Z"
},
"month": {
"limit": 500000,
"used": 1843,
"remaining": 498157,
"reset_in_seconds": 1159200,
"reset_at": "2026-09-01T00:00:00.000Z",
"bucket": 202608
}
}Fields
Code Samples
curl -H "Authorization: Bearer $QUALITLY_KEY" \
"https://backend.qualit.ly/api/v1/products/search?q=jordan+1&storefront=weidian"MCP Server
The same API is served as a hosted Model Context Protocol server, so Claude, Cursor, VS Code or any MCP client can query listings and QC sets without writing HTTP. Your API key, rate limits and tier rules carry over unchanged.
Server URL
https://backend.qualit.ly/api/mcpTransport
StreamableHTTP (POST)
Auth
Authorization: Bearer qc_live_…
Tools
Only the tools your tier can call are registered, so a Basic key never sees one it would be refused.
Claude Desktop, Cursor and VS Code
Add the server to claude_desktop_config.json (Claude → Settings → Developer), or to your editor's MCP settings.
Claude Desktop
{
"mcpServers": {
"qualitly": {
"url": "https://backend.qualit.ly/api/mcp",
"headers": {
"Authorization": "Bearer qc_live_YOUR_KEY"
}
}
}
}Cursor / VS Code
{
"mcp": {
"servers": {
"qualitly": {
"url": "https://backend.qualit.ly/api/mcp",
"headers": {
"Authorization": "Bearer qc_live_YOUR_KEY"
}
}
}
}
}Clients that support OAuth discovery — Claude.ai and ChatGPT among them — can skip the hardcoded key entirely: an unauthenticated request answers with a WWW-Authenticate header pointing at the server's OAuth metadata, and the client walks your users through a login page instead.
Check it works
# List the tools your key can see
curl -X POST https://backend.qualit.ly/api/mcp \
-H "Authorization: Bearer qc_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Plans & Tiers
Your tier is resolved from your account on every request, so an upgrade applies to the next call — no new key needed. Batch lookups, full QC image lists and ?url= extraction are the only endpoints gated above Basic; everything else differs by volume alone.
| Plan | / minute | / month | Search results | Batch + images |
|---|---|---|---|---|
| Basic | 30 | 1,000 | 5 | |
| Early Adopterlegacy | 40 | 3,000 | 10 | |
| Pro | 300 | 25,000 | 50 | |
| Pro+ | 1,000 | 500,000 | 100 | |
| Custom | Unlimited | Unlimited | 250 |
Early Adopter is legacy — held by existing accounts, never sold. Need more than Pro+? [email protected] sets up Custom limits.