/api/v1/onepiece/cards/{id} read:catalog 1
creditFetch a single One Piece Card Game card by its id. This is the cheapest way to hydrate a card you already know. Add `include=prices` for the embedded pricing object. Ids are matched case-insensitively, so `OPPR-681242` finds the card stored as `oppr-681242`; the response always carries the stored spelling.
GET /api/v1/onepiece/cards/swshp_ja-104vh?include=prices These inputs are shared across all docs pages, so an id entered here carries over.
{
"success": true,
"data": {
"id": "OP01-001",
"name": "Roronoa Zoro",
"number": "1",
"printed_number": "1",
"images": [
{
"type": "front",
"small": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.small.webp",
"medium": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.large.webp",
"large": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.large.webp"
}
],
"expansion": {
"id": "OP01",
"name": "Romance Dawn",
"total": 121,
"language": "English",
"language_code": "en",
"series": "One Piece",
"code": "OP01",
"printed_total": 121,
"release_date": "2022/12/02",
"logo": "https://api.rip.fun/storage/v1/object/public/tcg/sets/OP01.logo.png"
},
"language": "English",
"language_code": "en",
"tcgplayer_id": "454512",
"variants": [
{
"name": "normal",
"images": [
{
"type": "front",
"small": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.small.webp",
"medium": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.large.webp",
"large": "https://api.rip.fun/storage/v1/object/public/tcg/cards/OP01-001.large.webp"
}
]
}
],
"type": "Leader",
"power": "5000",
"attribute": "Slash",
"colors": [
"Red"
],
"rules": [
"[DON!! x1] [Your Turn] All of your Characters gain +1000 power."
],
"life": "5",
"subtypes": [
"Supernovas",
"Straw Hat Crew"
],
"rarity": "Leader",
"pricing": {
"currency": "USD",
"market": 2.03,
"is_stale": false,
"conditions": [
{
"condition": "NM",
"price": 2.03
},
{
"condition": "MP",
"price": 1.67
}
],
"graded": [
{
"company": "BGS",
"grade": "10",
"value": 889.5,
"low": 698.75,
"high": 1003.25,
"confidence": "low",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "CGC",
"grade": "10",
"value": 58.72,
"low": 48.76,
"high": 59.09,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "GENERIC",
"grade": "8",
"value": 22.5,
"low": 19.13,
"high": 25.87,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "GENERIC",
"grade": "9",
"value": 27,
"low": 22.95,
"high": 31.05,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "GENERIC",
"grade": "9.5",
"value": 44.19,
"low": 37.56,
"high": 50.82,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "PSA",
"grade": "10",
"value": 274.07,
"low": 258.44,
"high": 450.72,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "PSA",
"grade": "8",
"value": 22.5,
"low": 19.13,
"high": 25.87,
"confidence": "low",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "PSA",
"grade": "9",
"value": 31.65,
"low": 31.08,
"high": 32.41,
"confidence": "low",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "PSA",
"grade": "9.5",
"value": 148.5,
"low": 142.47,
"high": 244.25,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
},
{
"company": "SGC",
"grade": "10",
"value": 164.5,
"low": 154.5,
"high": 270.25,
"confidence": "med",
"value_kind": "feed",
"sold_count": 0
}
],
"market_updated_at": "2026-09-21T03:37:55.911Z",
"trend_7d": {
"direction": "down",
"percent": -7.31
}
}
}
}curl -X GET 'https://service.rip.fun/api/v1/onepiece/cards/swshp_ja-104vh?include=prices' \ -H 'X-API-Key: rip_…'
| Field | Type | Required | Description |
|---|---|---|---|
include | string | — | Set to `prices` to embed the pricing object on every returned object. **No surcharge** — metering is a flat 1 credit per request whatever the response carries, so hydrating a page of 100 with prices costs the same as without, and strictly less than a second call per row. |
data)| Field | Description |
|---|---|
data.id | Card id (variant printings carry a suffix, e.g. `…vh` for holofoil, `…vrh` for reverse holofoil) |
data.name / supertype / subtypes | Card identity + classification |
data.rarity / number / printed_number / artist | Print metadata |
data.images[] | `{ type, small, medium, large }`, `type` always `front`. Use `small` for grids and `large` for detail views. Two caveats: `medium` is always an alias of `large` (only two sizes are stored), and on cards whose source supplied a single rendition `small` is an alias too — it points at the same file as `large`. Compare the two URLs before assuming `small` is cheap; where they differ it is roughly 6× smaller. |
data.language / language_code | Card language: `English`/`en`, `Japanese`/`ja`. Each printing is its own object. |
data.tcgplayer_id | TCGplayer product id for cross-referencing, or null when we don’t have one |
data.expansion | Nested expansion object (id, name, series, total, release_date, logo, symbol, …) |
data.variants[] | `{ name, images[] }`, one self-describing element per card printing |
data.pricing | Present only with `include=prices` — and then always present, even where we hold nothing: `market` comes back `null` and the two arrays empty rather than the key being dropped. `{ currency, market, market_updated_at, is_stale, trend_7d, conditions[], graded[] }`, with every amount a **number** rather than a decimal string. `trend_7d` is `{ direction, percent }`, and it is the only trend window there is. See the Pricing data guide. |
data.pricing.conditions[] | `{ condition, price }` raw ladder (NM/LP/MP/HP/DMG) for the card’s variant — those two fields only |
data.pricing.graded[] | Reconciled graded value per company+grade: `{ company, grade, value, low, high, confidence, value_kind, sold_count, trend? }` |
Game fields on the Card object, on top of the shared ones above. All are optional and are omitted when we have no value, so a missing key means unknown.
| Field | What it holds |
|---|---|
type | Leader, Character, Event, Stage or DON!!. Replaces `supertype`, which is suppressed. DON!! rows are not deck cards, so a deck-building pool wants `-type:"DON!!"`. |
cost | Play cost, as a string. Metadata-only, so absent when the sync never captured it. |
power | Battle power, as a string. Replaces `hp`, which is suppressed. |
attribute | Slash, Strike, Ranged, Special or Wisdom. Dual-attribute cards join with a slash, e.g. `Slash/Special`, so filter with a substring: `attribute:Slash`. |
colors | Red, Green, Blue, Purple, Black, Yellow. Replaces `types`, which is suppressed. |
subtypes | Traits — crew and affiliation strings such as Straw Hat Crew, Supernovas. |
rules | Free-text effect lines, one per printed paragraph, as an array of strings. Never parsed or structured, but always markup-free — the promo printings store one HTML blob upstream and we split and clean it before returning it. |
counter | Printed Counter value on Characters (1000 / 2000), as a string. Sourced from the official card list, not from a price vendor — coverage is good but not complete, and Events, Stages and Leaders have no Counter at all. |
life | Leader Life total (4, 5, occasionally 6), as a string. Leaders only; same source and the same partial coverage. |
block | The Block icon printed in the lower-right corner. Verbatim from Bandai’s cardlist: `1`–`5`, or `X` for a printing with no numbered block. Multiple icons join with "/". Omitted where we have no value — absent is not the same answer as `X`. Read it as what the card shows, not as what is currently legal: see the note below before using it for format decisions. |
Each concept filters under the name it comes back as — that is the Query as column, and the one to write today. Also accepts is an older
spelling from when q resolved only against physical columns; it still
works, and a — there just means the field never had one. A concept whose Query as is — is not searchable at all; filter it client-side
after fetching. Querying an unknown field returns 400 invalid_query with a
suggested name rather than an empty result.
| Concept | Returned as | Query as | Also accepts |
|---|---|---|---|
| Card type | type | type:Leader | supertype:Leader |
| Cost | cost | cost:[1 TO 3] | — |
| Power | power | power:[5000 TO *] | hp:[5000 TO *] |
| Color | colors | colors:Red | types:Red |
| Attribute | attribute | attribute:Slash | — |
| Trait | subtypes | subtypes:"Straw Hat Crew" | — |
| Rules text | rules | rules:Blocker | — |
| Printing | variants[0].name | variant:altArt | — |
| Block | block | block:5 | — |
| Counter | counter | counter:1000 | — |
| Life | life | life:[4 TO 5] | — |
Every game field is optional and is omitted rather than sent as null, so a missing key means unknown — not zero and not empty.
Check `images[].small` before you rely on it. Roughly three in five One Piece cards were ingested with a single rendition, so `small` is the same URL as `large` — a full-size file where a thumbnail is expected. Compare the two strings and fall back to your own resizing when they match.
Scraping `rules` for Counter does not work. The `[Counter] +2000` string that appears on some cards is the Counter *effect keyword* — an ability played from hand — not the value printed in the corner. A Character with a printed +1000 Counter usually carries no `[Counter]` text at all, so a regex over `rules` returns a number for few cards and the wrong meaning for most of those. Life never appears in `rules` in any form.
Counter and Life are the only fields here we assemble ourselves rather than take from a catalog vendor, and coverage is still filling in. Treat a missing value as unknown, not as zero: Events, Stages and Leaders genuinely have no Counter, and only Leaders have Life, so absence is often correct — but it can also just mean we have not reached that card. Render nothing when the field is absent rather than a guessed or inferred value.
Where `counter` is absent we cannot tell you which kind of absent it is: the card may print no Counter, or we may simply not hold the value. The two are indistinguishable in the response, and the printed rules text does not settle it — cards missing a Counter carry ordinary ability text, not a `[Counter]` entry to parse. Anything that totals Counter across a deck is therefore incomplete rather than wrong, which is the safer of the two but still worth surfacing to your users.
Because coverage is partial, `counter:`, `life:` and `block:` filters narrow to the cards we hold a value for. Use them to explore, not to count — `counter:1000` is not the full set of 1000-Counter cards.
`block` is the printed icon, not the live regulation, and the two drift apart. Bandai reassigns blocks after print, and a reassignment never changes the artwork — so a card can be permanently Standard-legal while its printed icon says otherwise, and filtering `block:X` will miss it. Treat `block` as a catalog attribute you can display and group by; if you are deciding what is legal to play, take that from the current official regulation list, not from this field.
Block coverage is 77% of English printings and comes straight off Bandai’s cardlist, so it inherits their answers rather than a rule of thumb: their "booster packs 1–4 are Block 1, 5–8 are Block 2" shorthand disagrees with their own card list (OP16 reads Block 5), and OP05 lists different blocks for cards in the same set. The gap is the promo pool, whose printings carry synthetic numbers that match no page on the cardlist — the same reason `counter` stops at 56% of Characters.
Every field above is filterable under its own name, so a deck-building query reads the way the card does: `colors:Black cost:[1 TO 3] type:Character`. The older spellings in the table still resolve, so queries written against the DB-column names keep working.
`type` is a One Piece field. On `/pokemon` it is not a filter key at all — that game returns `supertype` and `types` as separate things — so `type:` there is a 400 naming both rather than a silent empty page.
| Status | Code | When |
|---|---|---|
| 404 | not_found | no such object for this game (a Pokémon id on `/onepiece` is "not found") |
See Errors for the response envelope and the full code list.