Every deck-detail response (GET /api/public/v1/games/{game}/decks/{id}) carries a
featured_cards array. It is the single, game-agnostic way to read a deck’s
special cards: the MTG commander, partner, and companion, and the Riftbound legend,
champion, and battlefields — all in the same shape, so one parser handles every game.
Entry shape
{
"slot": "battlefield",
"slotKey": "battlefield_1",
"label": "Battlefield",
"sortOrder": 0,
"foil": false,
"cardId": "a1b2c3…",
"name": "The Howling Abyss",
"imageUrl": "https://cdn.flexslot.gg/riftbound/UNL-131.webp",
"type_line": "Battlefield",
"set": "OGN",
"collector_number": "042"
}
| Field | Meaning |
|---|
slot | The base special-card type — the group key. legend, champion, battlefield, commander, partner, companion. Group by this. |
slotKey | The raw type including any ordinal. A deck with two battlefields yields battlefield_1 and battlefield_2, both with slot: "battlefield". Use this when you need to tell repeated slots apart. |
label | Human display label from the game’s configuration (e.g. "Battlefield", "Commander"). |
sortOrder | Ordering within a slot. The array is already returned in the game’s configured display order, then by sortOrder, so you can render it as-is. |
foil | Whether this copy is foil. |
cardId, name | Card identity. |
imageUrl | Absolute CDN URL to the card’s full-art image, or null if the card has no stored image. Check for null before rendering it as an <img> thumbnail. |
type_line, set, collector_number | Identifying card fields — enough to recognize the card without a second lookup. Any may be null. |
featured_cards is always present on deck-detail (it is [] for a deck with no
special cards). It is also returned on both deck-list endpoints —
GET /games/{game}/decks and GET /games/{game}/decks/my — when you pass
?include=summary, in the identical shape, so you can render special cards in a
list without a per-deck detail fetch. See List summary
fields. Without include=summary the list omits it; fetch
a single deck to read it.
List summary fields
Add ?include=summary to either list endpoint to receive, per deck, the same
featured_cards array shown above plus two more render-ready fields — no per-deck
detail fetch needed:
| Field | Meaning |
|---|
featured_cards | Identical shape to deck-detail (above). [] when the deck has none. |
section_counts | Object mapping section type → summed card quantity, e.g. { "maindeck": 60, "sideboard": 15 }. Keys are snake_case (maindeck, sideboard, rune_pool, …), exactly as the section types appear elsewhere. |
colors | Array of the deck’s color / identity strings. |
curl "https://api.flexslot.gg/api/public/v1/games/magic-the-gathering/decks?include=summary" \
-H "Authorization: Bearer $ACCESS_TOKEN"
All three keys are snake_case, and the two list endpoints return the exact same
field names and casing — one parser handles both. /decks/my enriches the
caller’s private decks too, not only public ones. The full per-section card
inventory (expanded_cards) is never on the list; it stays detail-only behind
?expand=cards.
Grouping by slot
slot is the group key; slotKey distinguishes repeated slots. Riftbound’s two
battlefields share slot: "battlefield" but keep distinct slotKeys:
const bySlot = {};
for (const c of deck.featured_cards) {
(bySlot[c.slot] ??= []).push(c);
}
// bySlot.legend -> [ { slotKey: "legend", … } ]
// bySlot.champion -> [ { slotKey: "champion", … } ]
// bySlot.battlefield -> [ { slotKey: "battlefield_1", … }, { slotKey: "battlefield_2", … } ]
Game coverage
The field is driven by each game’s special-card configuration, so it generalizes
without client changes:
| Game | slot values you’ll see |
|---|
| Magic: The Gathering | commander, partner, companion |
| Riftbound | legend, champion, battlefield |
A slot your code hasn’t seen before is still safe to render: label falls back to
a title-cased version of the type, and the card fields are always populated the same
way. Treat the set of slots as open-ended.