Skip to content

XDP Collectibles API

This document is for people who have been granted an API key.

Base URL:

https://api.xdp.lol

The API is read-only. It helps you find collectible metadata and the exact public R2 media URL for each asset. Media files are served directly by R2; this API only provides the correct mapping.

Authentication

Every route except /health requires your API key as a Bearer token:

Authorization: Bearer <your-api-key>

Example:

Authorization: Bearer k_example_id.your_secret_here

Keep your key private. Do not place it in browser/frontend JavaScript, screenshots, Git repositories, or public tools. If you believe it leaked, contact the API owner so it can be revoked.

Quick start

Check API status

No API key required:

curl https://api.xdp.lol/health

Example response:

{
  "revision": "2026-10-31T22:04:51.371303+00:00",
  "status": "ok"
}

PowerShell setup

$key = "k_example_id.your_secret_here"

Bash setup

KEY='k_example_id.your_secret_here'

Available requests

Method Path Use it when you need...
GET /health API availability and catalog revision.
GET /v1/items/{uuid} One exact asset by UUID.
GET /v1/products/{sku} A product and every asset belonging to it.
GET /v1/latest?limit=25 The most recently added products.
QUERY /v1/search A filtered, paginated collection search.

Look up one UUID

curl -H "Authorization: Bearer $KEY" \
  https://api.xdp.lol/v1/items/07863f54-2554-4b1b-b596-544381e168e8

PowerShell:

curl.exe -H "Authorization: Bearer $key" `
  "https://api.xdp.lol/v1/items/07863f54-2554-4b1b-b596-544381e168e8"

Example response:

{
  "sku_id": "legacy-file-pink_gyroscope",
  "name": "Pink Gyroscope",
  "product_type": "avatar-decoration",
  "group": "Discord 8th Birthday",
  "currently_available": false,
  "first_seen_at": "2026-10-30T01:46:38.084658+00:00",
  "last_seen_at": "2026-10-30T01:46:38.084658+00:00",
  "asset": {
    "slot": "avatar-primary",
    "role": "avatar-decoration",
    "uuid": "07863f54-2554-4b1b-b596-544381e168e8",
    "extension": ".png",
    "bytes": 354293,
    "r2_url": "https://r2.xdp.lol/07863f54-2554-4b1b-b596-544381e168e8.png"
  }
}

Use asset.r2_url to retrieve the media file.

Look up one product by SKU

curl -H "Authorization: Bearer $KEY" \
  https://api.xdp.lol/v1/products/1556807542322106429

This returns the product metadata plus its assets array. One product can have multiple files, for example PNG and WEBM versions, bundle art, or multiple display slots. Consume the entire array unless you specifically need one asset role or slot.

Get recently added products

curl -H "Authorization: Bearer $KEY" \
  "https://api.xdp.lol/v1/latest?limit=25"

limit defaults to 25 and must be between 1 and 100. Results are sorted by first-seen date, newest first.

Use the returned api_revision to identify the catalog version and has_more to decide whether more data is available.

Search the catalog

/v1/search uses the HTTP method QUERY. It is intentionally not GET or POST.

curl -X QUERY https://api.xdp.lol/v1/search \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"page":{"number":1,"size":25}}'

PowerShell:

curl.exe -X QUERY "https://api.xdp.lol/v1/search" `
  -H "Authorization: Bearer $key" `
  -H "Content-Type: application/json" `
  -d '{"page":{"number":1,"size":25}}'

All filters are optional. Empty or omitted filters search the complete catalog.

Search fields

Field Type Description
types string array Exact product type, such as avatar-decoration or nameplate.
groups string array Exact collection/group name, case-insensitive.
name_contains string Case-insensitive partial product-name match.
sku_ids string array Exact SKU IDs.
uuids string array Products containing one of these asset UUIDs.
asset_roles string array Products containing an asset with one of these exact roles.
active boolean true = listed in the newest shop snapshot; false = historical/retired.
sort.field string first_seen_at, last_seen_at, or name. Default: first_seen_at.
sort.direction string desc or asc. Default: desc.
page.number integer One-based page number. Default: 1.
page.size integer Products per page. Default: 25; allowed range: 1–100.

Values inside the same array are matched as OR. Different filters are matched as AND.

For example, this finds products that are both active and avatar decorations, with either requested group:

{
  "types": ["avatar-decoration"],
  "groups": ["Halloween", "Halloween '25"],
  "active": true,
  "sort": { "field": "name", "direction": "asc" },
  "page": { "number": 1, "size": 100 }
}

Halloween and Halloween '25 are separate exact groups.

Common searches

All avatar decorations:

{
  "types": ["avatar-decoration"],
  "page": { "number": 1, "size": 100 }
}

Name contains gyroscope:

{
  "name_contains": "gyroscope",
  "page": { "number": 1, "size": 25 }
}

Known batch of UUIDs:

{
  "uuids": [
    "07863f54-2554-4b1b-b596-544381e168e8",
    "65eb1ea4-a18a-48f2-82e8-1e35d95fe9e8"
  ],
  "page": { "number": 1, "size": 25 }
}

Paginated response

/v1/search and /v1/latest return this shape:

{
  "api_revision": "2026-10-31T22:04:51.371303+00:00",
  "total": 726,
  "page": 1,
  "page_size": 100,
  "has_more": true,
  "items": [
    {
      "sku_id": "1556807542322106429",
      "name": "Void Pumpkins",
      "product_type": "avatar-decoration",
      "group": "Dead by Daylight",
      "currently_available": true,
      "first_seen_at": "2026-10-17T17:20:05.471798+00:00",
      "last_seen_at": "2026-10-30T01:59:55.484982+00:00",
      "assets": [
        {
          "slot": "avatar-primary",
          "role": "avatar-decoration",
          "uuid": "be7a32fd-a522-4410-b39e-815321bdc71a",
          "extension": ".png",
          "bytes": 1567991,
          "r2_url": "https://r2.xdp.lol/be7a32fd-a522-4410-b39e-815321bdc71a.png"
        }
      ]
    }
  ]
}

Keep requesting the next page.number while has_more is true.

Errors and rate limits

Status Meaning
200 Request succeeded.
400 Invalid filter, sort field, sort direction, or page size.
401 Missing, malformed, revoked, or invalid API key.
403 Your key does not have the required permission.
404 UUID or SKU was not found.
405 Wrong request method. Use QUERY for /v1/search.
413 JSON request body exceeds 16 KiB.
429 Your per-minute key limit is exhausted. Wait for the next minute and retry.
500 Temporary server error. Retry later with backoff.

Errors return JSON:

{ "error": "key rate limit exceeded" }

Every key has its own assigned request-per-minute limit. Keep requests paginated, avoid unnecessary repeated searches, and apply exponential backoff after 429 or 500 responses.

Manage your own API keys

Once the API owner grants your Discord account access, use the XDP Collectibles Discord application to manage only your own keys. Key responses are ephemeral; only you can see them.

Command What it does
/api-keys Lists your key IDs, labels, states, RPM, and request totals.
/api-key-create label:<label> Creates a key, subject to your assigned maximum active-key limit. The raw key is shown once.
/api-key-pause id:<key-id> minutes:<optional> Stops a key immediately, indefinitely or for the selected duration.
/api-key-resume id:<key-id> Re-enables a paused key.
/api-key-rotate id:<key-id> Creates a replacement key and permanently revokes the old key.
/api-key-delete id:<key-id> Permanently revokes the selected key.
/api-key-usage id:<key-id> days:<optional> Shows recent request totals and your most-used routes.

Paused keys still count toward your assigned maximum, so pausing does not create extra key slots. Rotation replaces one key with one key and does not consume an extra slot.

Key-management actions are recorded for security and abuse investigation. Raw key secrets are never included in those audit records.

Important notes

  • The API automatically serves new catalog data after the catalog is updated.
  • A product may have more than one asset; do not assume assets[0] is always the only file.
  • currently_available: false does not mean the item is missing; it means it is not in the latest Discord shop snapshot.
  • The API is not intended for direct browser use. It does not provide permissive CORS headers, and browser code would expose your API key. Use a backend or secure proxy.

Support

When requesting support, provide the route, HTTP status, response body, approximate UTC time, and api_revision. Never send your complete API key.