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.
Minimal search
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: falsedoes 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.