API
Runeweave exposes a public JSON search API. It uses the same Scryfall-style syntax as the website. No API key needed; all you have to do is stay under the rate limit.
Quick example
curl 'https://runeweave.com/api/search?q=ahri&per_page=5'Endpoint
GET https://runeweave.com/api/search
Returns cards matching the query, paginated. CORS is enabled for all origins, so the API can be called from the browser.
Query parameters
| Name | Type | Description |
|---|---|---|
q | string | Search query. Same syntax as the website — see the syntax guide. Max 500 chars. Defaults to empty (all cards). |
page | integer | Page number, 1-indexed. Defaults to 1. |
per_page | integer | Results per page. Defaults to 30, max 100. |
sort | string | Sort order: name, name-desc, energy, energy-desc. Defaults to name. |
Rate limit
60 requests per minute per IP. Anonymous, fixed window. Every response includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Max requests allowed in the current window (60). |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets. |
Retry-After | Seconds until you can retry. Only sent on 429 responses. |
When you exceed the limit you'll get a 429 Too Many Requests:
{
"error": "rate_limited",
"message": "Rate limit exceeded. Try again in 42s."
}Status codes
| Code | Meaning |
|---|---|
200 | Search succeeded. Body contains results, possibly with warnings if a filter value was invalid. |
400 | Search failed due to a malformed query. Body has an error field. |
429 | Rate limit exceeded. Wait until X-RateLimit-Reset (or honor Retry-After) before retrying. |
Response shape
Example response for GET /api/search?q=ahri:
{
"query": "ahri",
"sort": "name",
"page": 1,
"perPage": 30,
"total": 4,
"totalPages": 1,
"cards": [
{
"id": "ahri-alluring",
"slug": "ahri-alluring",
"name": "Ahri, Alluring",
"domain": "Calm",
"domains": ["Calm"],
"cardType": "Unit",
"superType": "Champion",
"energy": 5,
"might": 4,
"power": 1,
"powerDomain": "Calm",
"text": "When I hold, you score 1 point.",
"tags": ["Ahri", "Ionia"],
"url": "https://runeweave.com/card/ahri-alluring",
"print": {
"publicCode": "OGN-066/298",
"collectorNumber": "66",
"rarity": "Rare",
"isSignature": false,
"illustrator": "League Splash Team",
"imageUrl": "https://runeweave.com/images/cards/OGN-066.webp",
"tcgplayerUrl": "https://www.tcgplayer.com/product/652842/...",
"set": {
"id": "OGN",
"code": "OGN",
"name": "Origins",
"releasedAt": "2025-10-31T00:00:00.000Z"
}
},
"price": {
"date": "2026-05-15T00:00:00.000Z",
"low": 0.68,
"mid": 1.09,
"high": 5,
"market": 1.05
}
}
],
"warnings": []
}Card fields
| Field | Type | Description |
|---|---|---|
id | string | URL-safe slug for this card. Use it in /card/{id}. |
slug | string | null | Same as id when present. |
name | string | Card name. |
domain | string | Primary domain: Chaos, Calm, Fury, Mind, Body, Order, Colorless. |
domains | string[] | All domains (dual-domain cards have two). |
cardType | string | Unit, Spell, Gear, Battlefield, Legend, or Rune. |
superType | string | null | Champion, Signature, Basic, Token, or null. |
energy | number | Energy cost. 0 for cards without one. |
might | number | null | Might value, or null. |
power | number | null | Power cost, or null. |
powerDomain | string | null | Domain of the power cost. |
text | string | Plain-text card description (markup stripped). |
tags | string[] | Tags like champion name, region, equipment. |
url | string | Canonical card page on Runeweave. |
print | object | null | The best-matching print for this card. See print fields below. |
price | object | null | Latest TCGPlayer price for the print, or null. |
Print fields
The print object describes the best-matching printing for the card. If your search has print-level filters (rarity, set, illustrator, etc.), this is the print that matched; otherwise it's the canonical first print.
| Field | Type | Description |
|---|---|---|
publicCode | string | Print identifier, e.g. OGN-066/298. |
collectorNumber | string | Collector number within the set. |
rarity | string | Common, Uncommon, Rare, Epic, Showcase, or Token. |
isSignature | boolean | True for showcase signature prints. |
illustrator | string | Artist credit. |
imageUrl | string | Absolute URL to the card image (WebP). |
tcgplayerUrl | string | null | TCGPlayer product page. |
set | object | null | { id, code, name, releasedAt }. |
Price fields
TCGPlayer pricing data, refreshed daily. All values are in USD. price may be null for unreleased cards and some promos.
| Field | Type | Description |
|---|---|---|
date | string | ISO date the price was fetched. |
low | number | null | TCGPlayer low price (USD). |
mid | number | null | TCGPlayer mid price (USD). |
high | number | null | TCGPlayer high price (USD). |
market | number | null | TCGPlayer market price (USD). |
Warnings
If a filter value isn't recognized (e.g. r:invalid), the response returns 200 with an empty card list and a populated warnings array. Each warning has the field, the bad value, and the list of valid options.
{
"query": "r:invalid",
"page": 1,
"perPage": 30,
"total": 0,
"totalPages": 0,
"cards": [],
"warnings": [
{
"field": "rarity",
"value": "invalid",
"validOptions": ["common", "uncommon", "rare", "epic", "showcase"]
}
]
}Examples
All rare Mind units with energy 3:
GET /api/search?q=d:mind+t:unit+r:rare+e:3Every card in the Unleashed set, 100 per page:
GET /api/search?q=s:unl&per_page=100Champions with might greater than 5, sorted by energy:
GET /api/search?q=is:champion+m:>5&sort=energy-descJavaScript fetch:
const res = await fetch('https://runeweave.com/api/search?q=ahri');
const { cards, total } = await res.json();
console.log(`Found ${total} cards`);Attribution & terms
The API is free to use. Please cache responses where reasonable and don't hammer it. Card data is sourced from Riot Games' public card gallery; pricing data is from tcgcsv.com. Runeweave is not affiliated with Riot Games. If you build something cool, let us know.