Skip to content

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. 1

    Get a key

    Sign in and create an API key from the developer dashboard.

  2. 2

    Make a request

    Send your key as a Bearer token in the Authorization header.

  3. 3

    Get data

    Receive JSON responses with product data and QC images.

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/products/weidian/7231368393

Authentication

Include a valid API key in the Authorization header using the Bearer scheme.

http
Authorization: Bearer qc_live_xxxxxxxxxxxxxxxxxxxxxxxx

Key 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.

Tier/ minute/ month
Basic301,000
Early Adopter403,000
Pro30025,000
Pro+1,000500,000
CustomUnlimitedUnlimited

/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.

X-RateLimit-LimitRequests allowed per minute on your tier, or "unlimited".
X-RateLimit-RemainingRequests left in the current minute.
X-RateLimit-ResetSeconds until the counter that blocked you resets.

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.

json
{
  "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.

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Product not found"
  }
}
400BAD_REQUESTInvalid request body or parameters.
401INVALID_KEYMissing, malformed or unknown API key.
401REVOKED_KEYThe key was revoked in the dashboard.
403IP_NOT_AUTHORIZEDRequest IP is not in the key's allowlist.
403FORBIDDENYour tier lacks access to this endpoint.
404NOT_FOUNDThe requested resource does not exist.
429RATE_LIMITEDPer-minute limit exceeded.
429QUOTA_EXCEEDEDMonthly quota exhausted; resets at UTC month rollover.
500INTERNALOur fault. Safe to retry with backoff.

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

GET/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.

storefrontrequiredstringOne of weidian, taobao, 1688.
listing_idrequiredstringThe storefront's own item ID.

Example

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/products/weidian/7231368393

Response

json
{
  "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

GET/products/search

Search 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.

qrequiredstringSearch text. Multiple words are AND-matched against the name and the product URL.
storefrontstringRestrict to weidian, taobao or 1688.
has_qcbooleanOnly listings that have QC photos.
limitintegerAsk for fewer than your plan's cap. Values above it are clamped down, never up.

No pagination. Each plan returns up to a fixed number of results per search; limit can ask for fewer, never more.

PlanMax results
Basic5
Early Adopter10
Pro50
Pro+100
Custom250

Example

bash
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

json
{
  "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

max_resultsYour plan's cap — the ceiling `limit` is clamped to.
countHow many rows this response actually carries.

Batch Products

Pro+
POST/products/batch

Resolve 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.

itemsrequiredarrayArray of { storefront, listing_id } objects. Capped at 100, or your plan's per-page limit if that is lower.

Request body

json
{
  "items": [
    { "storefront": "weidian", "listing_id": "7231368393" },
    { "storefront": "taobao", "listing_id": "123456789" }
  ]
}

Example

bash
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/batch

Response

json
{
  "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

POST/products/random

One random listing that has QC photos — for showcases, feeds, or sampling the catalogue. No body needed.

Example

bash
curl -X POST \
  -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/products/random

Response

json
{
  "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

GET/qc/{storefront}/{listing_id}

The QC photo count for a listing, plus the first three thumbnails — without pulling the full image list.

storefrontrequiredstringOne of weidian, taobao, 1688.
listing_idrequiredstringThe storefront's own item ID.

Example

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/qc/weidian/7231368393

Response

json
{
  "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+
GET/qc/{id}/images

Every 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.

idrequiredintegerNumeric product ID. Pass 0 when looking up by ?url=.
urlstringFull product URL to resolve instead of an ID. Takes precedence when present.

By product ID

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/qc/482910/images

By URL

bash
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

json
{
  "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

GET/me

Your account, the key that made the request and the tier it resolves to. Useful as a health check.

Example

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/me

Response

json
{
  "user": { "id": 12345, "username": "you" },
  "key": { "id": 7, "mode": "live" },
  "tier": "pro_plus"
}

Usage

GET/usage

Where 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

bash
curl -H "Authorization: Bearer qc_live_YOUR_KEY" \
  https://backend.qualit.ly/api/v1/usage

Response

json
{
  "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

tierOne of basic, early_adopter, pro, pro_plus, custom.
limit / remainingnull on the Custom tier, which is unlimited.
usedRequests in the current window. The minute counter resets every 60s, the month counter at UTC month rollover.
reset_atISO 8601, UTC.
bucketInternal YYYYMM key for the month counter.

Code Samples

bash
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/mcp

Transport

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.

get_productLook up a product by storefront and listing ID.
search_productsSearch by name, with storefront and has-QC filters.
get_products_batchLook up up to 100 products in one call.Pro+
random_productA random product that has QC photos.
get_qcQC count and the first 3 thumbnails.
get_qc_imagesFull CDN image list, by ID or URL.Pro+
get_meCurrent key, user and tier.
get_usagePer-minute and monthly quota status.

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

json
{
  "mcpServers": {
    "qualitly": {
      "url": "https://backend.qualit.ly/api/mcp",
      "headers": {
        "Authorization": "Bearer qc_live_YOUR_KEY"
      }
    }
  }
}

Cursor / VS Code

json
{
  "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

bash
# 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/ monthSearch resultsBatch + images
Basic301,0005
Early Adopterlegacy403,00010
Pro30025,00050
Pro+1,000500,000100
CustomUnlimitedUnlimited250

Early Adopter is legacy — held by existing accounts, never sold. Need more than Pro+? [email protected] sets up Custom limits.

Search

Cookies

We use them to keep you signed in and remember your saved products. Analytics only if you accept.