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
| Request | Returns |
|---|---|
| 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/:id | One card by its UUID. |
| GET /sets | Every set, with printing counts. |
| GET /sets/:code | One set by code, e.g. ogn. |
| GET /bulk-data | Index of the bulk exports. |
| GET /bulk/cards | The whole catalogue: 1432 printings, ~1.2 MB. |
| GET /bulk/prices | TCGplayer prices for 1409 printings. Refreshed daily. |
| GET /prices/:riftboundId | Prices for one printing. |
| GET /tags?kind=&q= | Community tags, most-used first. kind is function or art; q filters by name. |
| GET /tags/:kind/:slug | One tag: description, count, creator, and the search that lists its cards. |
| GET /cards/:id/tags | Every community tag on one printing: function tags from its card, art tags of its own. |
| GET /bulk/tags | Every tagging, one row per (tag, printing). What the site builds from. |
| GET /health | Liveness check. |
Searching
/cards/search takes the same query syntax as the site's search
box, documented in full on the syntax guide.
| Example | Finds |
|---|---|
| /cards/search?q=t:unit d:fury e<=3 | Cheap Fury units. |
| /cards/search?q=t:gear p:1 | Gear costing one rune. |
| /cards/search?q=s:ogn r:epic | Epics 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
| Field | Meaning |
|---|---|
| object | Always "card". |
| id | Stable UUID for this printing. |
| oracle_id | Shared by every printing of the same card. |
| lang | Language of the text fields. Only "en" today. |
| name | Printed name, including any variant suffix, e.g. "Annie, Dark Child (Metal)". |
| oracle_name | The base name shared by every printing, e.g. "Annie, Dark Child". |
| type | Unit, Spell, Gear, Legend, Battlefield or Rune. |
| domains | Lowercased array. Also which runes may pay the rune cost. |
| energy | Energy cost. null when there is none. |
| power | Rune cost: how many runes are recycled to play it. null when there is none. |
| might | Combat stat on units. null otherwise. |
| keywords | Lowercased array. |
| tags | Lowercased array. Searchable with tag:. |
| rules_text | Plain text. Keeps :rb_*: symbol shortcodes. |
| flavor_text | Plain text, or null. |
| set | Set code, lowercased, e.g. "ogn". |
| set_name | Full set name. |
| collector_number | As printed, zero-padded, e.g. "017". Letter-prefixed (t, r, s) for tokens, runes and special promos. |
| rarity | common, uncommon, rare, epic, showcase or promo. |
| artist | Illustrator, or null. |
| variant | alternate, overnumbered, signature or null. Metal promos carry it in the name instead. |
| riftbound_id | Riot's own id, e.g. ogn-025-298. Not unique: 52 promos share one. |
| porodb_uri | Canonical path for this printing on rifthunt.com. |
| images | Object with full and thumb URLs. |
| tcg_id | TCGplayer product id, or null. Build your own link with it if you prefer. |
| purchase_uris | Object with tcgplayer (an affiliate link, see below) and cardmarket. |
| prices | TCGplayer 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.
| Endpoint | Browser | Edge |
|---|---|---|
| /cards/search | 60s browser | 1h edge, 24h stale-while-revalidate |
| /cards/:id, /cards/named | 1h browser | 24h edge |
| /sets, /sets/:code | 1h browser | 24h edge |
| /bulk/cards | 1h browser | 24h edge, 7d stale-while-revalidate |
| /bulk/prices, /prices/:id | 5–10m browser | 15–30m edge, 24h stale-while-revalidate |
| /tags, /cards/:id/tags, and any search using otag: or art: | 30s browser | 1m 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.