API guide

Every card on this site is available as JSON from https://api.rifthunt.com. No key, no signup, no quota: all requests are GET, all responses are application/json, and CORS is open so you can call it straight from a browser app.

Fair use

There is no hard rate limit, which is a request rather than a promise. Keep bursts under roughly 10 requests per second and put a short delay between calls in a loop.

If you want more than a few hundred cards, do not crawl: download the bulk export once and work locally. It is one request instead of a thousand and it is faster for you.

Send a User-Agent that identifies your project. If something misbehaves, that is the difference between getting an email and getting blocked.

Endpoints

RequestReturns
GET /cards/search?q=…Search. Same syntax as the site (see the syntax guide). Add unique=prints for every printing.
GET /cards/named?exact=…One card by exact name.
GET /cards/:idOne card by its UUID.
GET /setsEvery set, with printing counts.
GET /sets/:codeOne set by code, e.g. ogn.
GET /bulk-dataIndex of the bulk exports.
GET /bulk/cardsThe whole catalogue: 1432 printings, ~1.2 MB.
GET /bulk/pricesTCGplayer prices for 1409 printings. Refreshed daily.
GET /prices/:riftboundIdPrices for one printing.
GET /tags?kind=&q=Community tags, most-used first. kind is function or art; q filters by name.
GET /tags/:kind/:slugOne tag: description, count, creator, and the search that lists its cards.
GET /cards/:id/tagsEvery community tag on one printing: function tags from its card, art tags of its own.
GET /bulk/tagsEvery tagging, one row per (tag, printing). What the site builds from.
GET /healthLiveness check.

Searching

/cards/search takes the same query syntax as the site's search box, documented in full on the syntax guide.

ExampleFinds
/cards/search?q=t:unit d:fury e<=3Cheap Fury units.
/cards/search?q=t:gear p:1Gear costing one rune.
/cards/search?q=s:ogn r:epicEpics in Origins.

Results are one printing per card by default: reprints and variants collapse into a single entry, and the rest are on that card's page. A query matching nothing returns 404, not an empty list.

Response shape

Lists are wrapped in an envelope:

{
  "object": "list",
  "total_cards": 41,
  "has_more": false,
  "next_page": null,
  "data": [ /* card objects */ ]
}

Errors use the same convention, with the HTTP status repeated in the body:

{
  "object": "error",
  "status": 404,
  "code": "not_found",
  "details": "Your query didn't match any cards. Adjust your search terms."
}

The card object

FieldMeaning
objectAlways "card".
idStable UUID for this printing.
oracle_idShared by every printing of the same card.
langLanguage of the text fields. Only "en" today.
namePrinted name, including any variant suffix, e.g. "Annie, Dark Child (Metal)".
oracle_nameThe base name shared by every printing, e.g. "Annie, Dark Child".
typeUnit, Spell, Gear, Legend, Battlefield or Rune.
domainsLowercased array. Also which runes may pay the rune cost.
energyEnergy cost. null when there is none.
powerRune cost: how many runes are recycled to play it. null when there is none.
mightCombat stat on units. null otherwise.
keywordsLowercased array.
tagsLowercased array. Searchable with tag:.
rules_textPlain text. Keeps :rb_*: symbol shortcodes.
flavor_textPlain text, or null.
setSet code, lowercased, e.g. "ogn".
set_nameFull set name.
collector_numberAs printed, zero-padded, e.g. "017". Letter-prefixed (t, r, s) for tokens, runes and special promos.
raritycommon, uncommon, rare, epic, showcase or promo.
artistIllustrator, or null.
variantalternate, overnumbered, signature or null. Metal promos carry it in the name instead.
riftbound_idRiot's own id, e.g. ogn-025-298. Not unique: 52 promos share one.
porodb_uriCanonical path for this printing on rifthunt.com.
imagesObject with full and thumb URLs.
tcg_idTCGplayer product id, or null. Build your own link with it if you prefer.
purchase_urisObject with tcgplayer (an affiliate link, see below) and cardmarket.
pricesTCGplayer prices per finish, or null if we have none. See below.

One printing or all of them

By default search returns one printing per card: the plain one, without a variant suffix, the same as Scryfall. Add unique=prints to get every printing, which is what you want for prices: a card and its Metal promo are separate products fifty times apart in value.

curl -s "https://api.rifthunt.com/cards/search?q=annie&unique=prints"

/cards/named?exact= accepts either form. The base name returns the plain printing; a printed name such as Annie, Dark Child (Metal) returns that printing.

Bulk data

/bulk/cards returns all 1432 printings in one response, about 1.2 MB. It is the same file the site itself builds from, so it will never disagree with what you see here. Fetch it once a day at most, since card data only changes when a set does.

curl -s https://api.rifthunt.com/bulk/cards > cards.json

Community tags

Cards carry two kinds of community tag, the way Scryfall's do: function tags on the card (what it does, searchable as otag:removal) and art tags on a printing (what the picture shows, art:dragon). Reading them needs no account. Adding them does: sign in on the tagger, which uses the same API with a bearer token. Tags can change at any time, so cache them for minutes, not days.

curl -s "https://api.rifthunt.com/cards/search?q=otag:removal"

Prices

Prices are a separate export, because they change on a completely different schedule to the catalogue. /bulk/prices returns 1423 rows, one per printing with a TCGplayer product, of which 1409 have a current market price. The rest are listed products with nothing for sale right now, so every field is null. Refreshed daily.

curl -s https://api.rifthunt.com/bulk/prices > prices.json

Normal and foil are reported separately, under finishes, because TCGplayer lists them as separate products and they diverge by orders of magnitude: the same card can be seven cents normal and $185 foil.

Each row also carries a purchaseUri, an affiliate deep link to that exact printing on TCGplayer. See affiliate links.

Each row is keyed by riftboundId, collector and slug together, not by riftboundId alone. The 52 “(Metal)” promos share an id with their base printing and are separate products at very different prices, so keying on the id by itself will silently give you the wrong one.

Affiliate links

The purchase_uris.tcgplayer value on every card, and the purchaseUri on every price row, are affiliate links. PoroDB earns a commission when someone buys through one. They are how this API stays free and keyless, and you are welcome to use them in your own app.

Caching

Responses are cached at Cloudflare's edge, so most requests never reach the origin. Respect these and you will rarely notice a limit exists.

EndpointBrowserEdge
/cards/search60s browser1h edge, 24h stale-while-revalidate
/cards/:id, /cards/named1h browser24h edge
/sets, /sets/:code1h browser24h edge
/bulk/cards1h browser24h edge, 7d stale-while-revalidate
/bulk/prices, /prices/:id5–10m browser15–30m edge, 24h stale-while-revalidate
/tags, /cards/:id/tags, and any search using otag: or art:30s browser1m edge, 5m stale-while-revalidate

Examples

# shell
curl -s "https://api.rifthunt.com/cards/search?q=t:gear%20p:1"

# PowerShell: note curl is an alias for Invoke-WebRequest, so use the native cmdlet
Invoke-RestMethod "https://api.rifthunt.com/sets" | Select-Object -ExpandProperty data

# browser / Node
const res = await fetch("https://api.rifthunt.com/cards/named?exact=Blind Fury");
const card = await res.json();
console.log(card.energy, card.power, card.domains);

Terms

Free for any use, commercial included. PoroDB is unofficial Fan Content under Riot Games' Legal Jibber Jabber policy: card names, text and images are Riot's, and your project inherits the same terms. A link back is appreciated but not required.