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

NameTypeDescription
qstringSearch query. Same syntax as the website — see the syntax guide. Max 500 chars. Defaults to empty (all cards).
pageintegerPage number, 1-indexed. Defaults to 1.
per_pageintegerResults per page. Defaults to 30, max 100.
sortstringSort order: name, name-desc, energy, energy-desc. Defaults to name.

Rate limit

60 requests per minute per IP. Anonymous, fixed window. Every response includes:

HeaderMeaning
X-RateLimit-LimitMax requests allowed in the current window (60).
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetUnix timestamp (seconds) when the window resets.
Retry-AfterSeconds 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

CodeMeaning
200Search succeeded. Body contains results, possibly with warnings if a filter value was invalid.
400Search failed due to a malformed query. Body has an error field.
429Rate 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

FieldTypeDescription
idstringURL-safe slug for this card. Use it in /card/{id}.
slugstring | nullSame as id when present.
namestringCard name.
domainstringPrimary domain: Chaos, Calm, Fury, Mind, Body, Order, Colorless.
domainsstring[]All domains (dual-domain cards have two).
cardTypestringUnit, Spell, Gear, Battlefield, Legend, or Rune.
superTypestring | nullChampion, Signature, Basic, Token, or null.
energynumberEnergy cost. 0 for cards without one.
mightnumber | nullMight value, or null.
powernumber | nullPower cost, or null.
powerDomainstring | nullDomain of the power cost.
textstringPlain-text card description (markup stripped).
tagsstring[]Tags like champion name, region, equipment.
urlstringCanonical card page on Runeweave.
printobject | nullThe best-matching print for this card. See print fields below.
priceobject | nullLatest 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.

FieldTypeDescription
publicCodestringPrint identifier, e.g. OGN-066/298.
collectorNumberstringCollector number within the set.
raritystringCommon, Uncommon, Rare, Epic, Showcase, or Token.
isSignaturebooleanTrue for showcase signature prints.
illustratorstringArtist credit.
imageUrlstringAbsolute URL to the card image (WebP).
tcgplayerUrlstring | nullTCGPlayer product page.
setobject | 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.

FieldTypeDescription
datestringISO date the price was fetched.
lownumber | nullTCGPlayer low price (USD).
midnumber | nullTCGPlayer mid price (USD).
highnumber | nullTCGPlayer high price (USD).
marketnumber | nullTCGPlayer 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:3

Every card in the Unleashed set, 100 per page:

GET /api/search?q=s:unl&per_page=100

Champions with might greater than 5, sorted by energy:

GET /api/search?q=is:champion+m:>5&sort=energy-desc

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