SWU API
Star Wars Unlimited Data API
Overview
The SWU API provides programmatic access to Star Wars Unlimited card data, tournament results, decklists, archetypes, taxonomy, and sync feeds. All responses are JSON unless an endpoint explicitly returns an image.
Public endpoints (no authentication required when API auth is enabled): Health, Docs, QR decode, Cards & Sets, Export, Archetypes, Base Groups, Metas, Merges, Deletions, Findings, and Deck Image.
Private endpoints (API key required when API auth is enabled): Tournaments, Players, Accounts, Venues, Team Prefixes, Matches, Standings, Decklists, Archetype Groups, Subarchetypes, and SWUDB L1 feeds. Pass your key as a Bearer token: Authorization: Bearer <key>
Base URL
https://api.swuapi.com
Incremental Sync
Primary L2 list endpoints support a keep-my-mirror-in-sync workflow with ?since=, ?after=, and ?limit=. Smaller reference feeds and append-only event streams have endpoint-specific pagination noted below.
Parameters
| Parameter | Type | Description |
|---|---|---|
since | string (ISO 8601) | Return only rows whose updated_at >= since. Every L2 table stamps updated_at on every upsert, so this is a reliable high-water mark. |
after | string (uuid) | Forward cursor. Pass the next_cursor returned by the previous response. Pagination is ordered by uuid ASC (UUID v7 is time-ordered). |
limit | integer | Page size. Default 200; max 1000 (500 on heavier endpoints). |
Contract
- UUID v7 primary keys. Every L2 row has a time-ordered
uuid. Use it everywhere — for lookups, joins, and pagination. Do not paginate by source IDs (melee_id,strapi_id, etc.). ?since=forces cursor (uuid-ASC) ordering on cursor-paginated L2 lists. When?since=is present, those responses are ordered byuuidASC and the emittednext_cursoris valid for the next page. Without?since=or?after=, list endpoints may return in a display order (e.g. tournament date DESC) for human browsing.- Terminal condition. On cursor-paginated endpoints, when the returned row count is less than
limit, you have reached the end of the window. Advancesinceto the maxupdated_atyou observed and poll again later. - Merges. When swuapi consolidates duplicates (archetypes, players, accounts, tournaments, venues, etc.) the old row vanishes from list endpoints. Poll
GET /merges?since=to discover re-points and update your local foreign keys. Coveredentity_typevalues:tournament,player,account,decklist,match,standing,venue,archetype.cardmerges never emit —cards.uuidis write-once.
Cursor-Paginated L2 Lists
/cards, /tournaments, /players, /accounts, /matches, /decklists, /standings, /venues, /archetypes, /subarchetypes, and /findings.
Endpoint-Specific Sync
/sets, /archetype-groups, and /base-groups support ?since= without cursor pagination. /merges and /deletions are append-only event streams filtered by ?since= and optional ?entity_type=. /swudb/decklists uses ?since= plus offset pagination because it exposes L1 source data, not L2 UUID rows.
Example: mirror every match
let since = lastSyncWatermark // ISO string from previous run
let after = null
let maxSeen = since
while (true) {
const url = `${base}/matches?since=${since}${after ? `&after=${after}` : ''}&limit=500`
const { matches, pagination } = await (await fetch(url, { headers })).json()
for (const m of matches) {
upsert(m)
if (m.updated_at > maxSeen) maxSeen = m.updated_at
}
if (matches.length < 500) break
after = pagination.next_cursor
}
saveWatermark(maxSeen)
Health check endpoint. Returns server status and last scrape info.
curl https://api.swuapi.com/health
const response = await fetch('https://api.swuapi.com/health');
const data = await response.json();
console.log(data.status); // "healthy"
{
"status": "healthy",
"cardCount": 5560,
"tournamentCount": 130,
"playerCount": 2400,
"accountCount": 2700,
"matchCount": 18000,
"decklistCount": 5200,
"lastScrape": {
"completedAt": "2024-01-15T06:00:00.000Z",
"status": "success",
"durationMs": 42000,
"stats": { /* scraper stats */ }
},
"lastTournamentScrape": {
"completedAt": "2026-03-20T07:00:00.000Z",
"status": "success",
"durationMs": 180000,
"stats": { /* scraper stats */ }
},
"liveScraper": {
"alive": true,
"lastRun": "2026-03-20T12:10:00.000Z",
"expiresAt": "2026-03-20T12:15:00.000Z"
},
"uptime": 3600
}
List all card sets/expansions.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO 8601 timestamp. Returns only sets with updated_at >= since. This endpoint is not cursor-paginated. |
curl https://api.swuapi.com/sets
const response = await fetch('https://api.swuapi.com/sets');
const { sets } = await response.json();
sets.forEach(set => {
console.log(`${set.code}: ${set.name}`);
});
{
"sets": [
{
"code": "SOR",
"name": "Spark of Rebellion",
"release_date": "2024-03-08",
"total_cards": 252
},
{
"code": "SHD",
"name": "Shadows of the Galaxy",
"release_date": "2024-07-12",
"total_cards": 262
}
]
}
Get a single set by its code.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
code |
string | Set code (e.g., SOR, SHD, TWI) |
curl https://api.swuapi.com/sets/SOR
const setCode = 'SOR';
const response = await fetch(`https://api.swuapi.com/sets/${setCode}`);
const set = await response.json();
console.log(set.name); // "Spark of Rebellion"
{
"code": "SOR",
"name": "Spark of Rebellion",
"release_date": "2024-03-08",
"total_cards": 252
}
List cards with pagination and optional filtering.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 100 | Number of cards to return (max 500) |
offset |
integer | 0 | Number of cards to skip |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
set |
string | - | Filter by set code (e.g., SOR, SHD) |
type |
string | - | Filter by type (Leader, Unit, Event, Upgrade, Base) |
rarity |
string | - | Filter by rarity (Common, Uncommon, Rare, Legendary, Special) |
name |
string | - | Search by card name or subtitle (case-insensitive partial match) |
since |
string | - | ISO 8601 timestamp. Returns only cards with updated_at >= since; pairs with after for cursor sync. |
# Get first 100 cards
curl https://api.swuapi.com/cards
# Get leaders from Spark of Rebellion
curl "https://api.swuapi.com/cards?set=SOR&type=Leader"
# Search by name
curl "https://api.swuapi.com/cards?name=Bossk"
# Paginate through results
curl "https://api.swuapi.com/cards?limit=50&offset=100"
// Get all leaders from SOR
const params = new URLSearchParams({
set: 'SOR',
type: 'Leader',
limit: 50
});
const response = await fetch(
`https://api.swuapi.com/cards?${params}`
);
const { cards, pagination } = await response.json();
console.log(`Found ${pagination.total} cards`);
cards.forEach(card => console.log(card.name));
{
"cards": [
{
"id": "SOR_005",
"name": "Luke Skywalker",
"subtitle": "Faithful Friend",
"type": "Leader",
"rarity": "Special",
// ... see Card Object for all fields
}
],
"pagination": {
"limit": 100,
"offset": 0,
"total": 5560
}
}
Get a single card by any identifier: UUID, external_id (integer), collector_number (SOR_005), or card name slug (e.g., "entrenched").
Variant note: collector_number is shared between variants (e.g. SOR_005 is both Luke Standard and Luke Foil). Lookups by collector_number or name slug always return the Standard variant by default. Use ?variant= to request a different variant. UUID and external_id are unique per variant and ignore this parameter.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | int | uuid | UUID, external_id (integer), collector_number (e.g., SOR_005), or card name slug |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
variant |
string | Standard |
Filter by variant_type when looking up by collector_number or name slug. Common values: Standard, Hyperspace, Showcase. Use all to return an array of every variant sharing the same collector_number. Ignored for UUID and external_id lookups. |
# By UUID (unique, stable)
curl https://api.swuapi.com/cards/59e4854c-bd67-47f2-98c9-815d31736928
# By external_id (unique per variant)
curl https://api.swuapi.com/cards/5
# By collector_number — returns Standard variant by default
curl https://api.swuapi.com/cards/SOR_005
# By collector_number — request Hyperspace variant explicitly
curl https://api.swuapi.com/cards/SOR_005?variant=Hyperspace
# By collector_number — return all variants as an array
curl https://api.swuapi.com/cards/SOR_005?variant=all
# By slug
curl https://api.swuapi.com/cards/entrenched
const response = await fetch(
'https://api.swuapi.com/cards/59e4854c-bd67-47f2-98c9-815d31736928'
);
const card = await response.json();
console.log(card.uuid); // "59e4854c-..."
console.log(card.collector_number); // "SOR_005"
console.log(card.external_id); // 5
{
"uuid": "59e4854c-bd67-47f2-98c9-815d31736928",
"external_id": 5,
"collector_number": "SOR_005",
"external_uid": "2579145458",
"name": "Luke Skywalker",
"subtitle": "Faithful Friend",
"setCode": "SOR",
"cardNumber": "5",
"type": "Leader",
"type2": "Leader Unit",
"rarity": "Special",
"cost": 6,
"power": 4,
"hp": 7,
"arena": "Ground",
"aspects": ["Vigilance", "Heroism"],
"traits": ["Force", "Rebel"],
"keywords": [],
"variantType": "Standard",
"text": "Action [1 resource, exhaust]: Give a Shield token...",
"deployBox": "On Attack: You may give another unit a Shield token.",
"epicAction": "Epic Action: If you control 6 or more resources...",
"isUnique": true,
"isLeader": true,
"frontImageUrl": "https://cdn.starwarsunlimited.com/...",
"backImageUrl": "https://cdn.starwarsunlimited.com/...",
"artist": "Borja Pindado",
"variants": [981, 9745],
"variantOf": null,
"reprints": [100],
"reprintOf": null
}
Export all cards and sets as a single JSON payload. Useful for bulk imports or syncing.
# Download full export
curl https://api.swuapi.com/export/all -o cards.json
# Pipe to jq for processing
curl -s https://api.swuapi.com/export/all | jq '.meta'
const response = await fetch(
'https://api.swuapi.com/export/all'
);
const { cards, sets, meta } = await response.json();
console.log(`Total cards: ${meta.totalCards}`);
console.log(`Total sets: ${meta.totalSets}`);
console.log(`Last scraped: ${meta.lastScrapedAt}`);
// Process all cards
const leaders = cards.filter(c => c.type === 'Leader');
console.log(`Found ${leaders.length} leaders`);
{
"cards": [
{ /* card objects */ }
],
"sets": [
{ /* set objects */ }
],
"meta": {
"totalCards": 5560,
"totalSets": 19,
"lastScrapedAt": "2024-01-15T06:00:00.000Z",
"exportedAt": "2024-01-15T12:00:00.000Z"
}
}
Export one L2 entity table. Use this for bulk snapshots when you want one entity type instead of the card-only /export/all payload.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
entity | string | One of cards, sets, tournaments, venues, players, accounts, matches, decklists, standings, archetypes. |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | - | UUID cursor. When provided, rows after this UUID are returned in UUID order. |
limit | integer | all rows | Optional page size. Max 5000. If cursor is provided without limit, defaults to 1000. |
curl "https://api.swuapi.com/export/tournaments?limit=1000"
{
"data": [ { /* rows */ } ],
"total": 130,
"has_more": false,
"next_cursor": null
}
Decode a deck QR image and fetch deck JSON from a supported source. Supported QR URLs are SWUDB, SWUBase, and SWU Forge deck links.
Request Body
Send multipart/form-data with a single image file field named image. Maximum image size is 10 MB.
curl -X POST https://api.swuapi.com/qr/decode \
-F "image=@deck-qr.png"
Returns 400 for invalid uploads, 422 when no QR code or recognized deck URL is found, and JSON deck data on success.
List SWU tournaments. Includes competitive events (PQ, SQ, RQ, GC, LCQ), Store Showdowns (SS), community events (COM), and casual side events (CAS).
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of tournaments to return (max 200) |
offset |
integer | 0 | Number of tournaments to skip |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
tier |
string | - | Filter by tier: PQ, SQ, RQ, GC, LCQ, SS, COM, CAS |
format |
string | - | Filter by format: Premier, Limited |
official |
boolean | - | Filter by official status (true = FFG-sanctioned, false = community) |
country |
string | - | Filter by venue country code or country name when available |
status |
string | - | Filter by tournament status: upcoming, live, or completed |
include_upcoming |
boolean | true | Set to false to hide upcoming tournaments in browse results |
since |
string | - | ISO 8601 timestamp. Returns only tournaments with updated_at >= since; pairs with after for cursor sync. |
missing |
string | - | Comma-separated ingest-health tokens: decklists, top_cut, standings. Returns completed events with matches that are missing those artifacts. |
date_after |
string | - | Date cutoff (YYYY-MM-DD) for tournament date. Useful with missing= checks. |
# List all tournaments
curl https://api.swuapi.com/tournaments
# Filter by tier and format
curl "https://api.swuapi.com/tournaments?tier=PQ&format=Premier"
const response = await fetch(
'https://api.swuapi.com/tournaments?tier=SQ'
);
const { tournaments, pagination } = await response.json();
console.log(`Found ${pagination.total} Sector Qualifiers`);
{
"tournaments": [
{
"melee_id": 67890,
"name": "Star Wars: Unlimited Planetary Qualifier Austin",
"display_name": "Planetary Qualifier (SEC) — Austin, TX, US",
"date": "2026-02-15T00:00:00.000Z",
"tier": "PQ",
"tier_level": "competitive",
"format": "Premier",
"official": true,
"organizer": "Emerald Tavern Games",
"player_count": 64,
"has_day_two": true,
"day_one_swiss_rounds": 8,
"day_two_swiss_rounds": 4,
"round_structure": {
"has_day_two": true,
"total_swiss_rounds": 12,
"day_two_start_round": 9,
"days": [
{ "day": 1, "start_round": 1, "end_round": 8, "swiss_round_count": 8 },
{ "day": 2, "start_round": 9, "end_round": 12, "swiss_round_count": 4 }
]
},
"melee_url": "https://melee.gg/Tournament/View/67890",
"event_type": "main",
"winner_player_uuid": "019d240f-409b-7786-9dbe-74e91e7f1a77"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 130
}
}
Get a single tournament by UUID or melee.gg tournament ID.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | integer | Tournament UUID or melee.gg tournament ID |
curl https://api.swuapi.com/tournaments/67890
{
"melee_id": 67890,
"name": "Star Wars: Unlimited Planetary Qualifier Austin",
"date": "2026-02-15T00:00:00.000Z",
"tier": "PQ",
"format": "Premier",
"organizer": "Emerald Tavern Games",
"player_count": 64,
"has_day_two": true,
"day_one_swiss_rounds": 8,
"day_two_swiss_rounds": 4,
"round_structure": {
"has_day_two": true,
"total_swiss_rounds": 12,
"day_two_start_round": 9,
"days": [
{ "day": 1, "start_round": 1, "end_round": 8, "swiss_round_count": 8 },
{ "day": 2, "start_round": 9, "end_round": 12, "swiss_round_count": 4 }
]
},
"melee_url": "https://melee.gg/Tournament/View/67890",
"event_type": "main"
}
List live and upcoming tournaments with current-round metadata. Multi-day melee events include inferred Day 1 / Day 2 Swiss structure and the current round’s tournament day.
curl https://api.swuapi.com/tournaments/live
{
"tournaments": [
{
"melee_id": 414243,
"name": "Sector Qualifier - Atlanta - Saturday - 10:00 am",
"status": "live",
"has_day_two": true,
"day_one_swiss_rounds": 8,
"day_two_swiss_rounds": 4,
"round_structure": {
"day_two_start_round": 9,
"days": [
{ "day": 1, "start_round": 1, "end_round": 8, "swiss_round_count": 8 },
{ "day": 2, "start_round": 9, "end_round": 12, "swiss_round_count": 4 }
]
},
"current_round": 8,
"current_round_name": "Round 8",
"current_round_day": 1,
"round_count": 15
}
]
}
Return all rounds for a tournament. Each round includes round_stage (swiss or top_cut) and tournament_day inferred from melee’s public event schedule when available.
curl https://api.swuapi.com/tournaments/414243/rounds
{
"round_structure": {
"has_day_two": true,
"total_swiss_rounds": 12,
"day_two_start_round": 9,
"days": [
{ "day": 1, "start_round": 1, "end_round": 8, "swiss_round_count": 8 },
{ "day": 2, "start_round": 9, "end_round": 12, "swiss_round_count": 4 }
]
},
"rounds": [
{
"round_number": 8,
"round_name": "Round 8",
"is_top_cut": false,
"round_stage": "swiss",
"tournament_day": 1,
"pairing_count": 64
},
{
"round_number": 9,
"round_name": "Round 9",
"is_top_cut": false,
"round_stage": "swiss",
"tournament_day": 2,
"pairing_count": 0
},
{
"round_number": 100,
"round_name": "Quarterfinals",
"is_top_cut": true,
"round_stage": "top_cut",
"tournament_day": 2
}
]
}
Return standings for one tournament. Without round, returns the latest available round and falls back to final standings for historical events. With round=N, returns that per-round live standing when the live scraper observed it.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | integer | Tournament UUID or melee.gg tournament ID. |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
round | integer | latest | Specific round number to fetch. |
curl "https://api.swuapi.com/tournaments/414243/standings?round=8"
Get all match results for a tournament by UUID or melee.gg ID. Add ?round=N to fetch one round. Includes player names via join and a derived draw_type field (intentional, played, or null).
curl https://api.swuapi.com/tournaments/67890/matches
{
"tournament": { "melee_id": 67890, "name": "PQ Austin", ... },
"matches": [
{
"uuid": "019d9557-...",
"round_number": 1,
"is_top_cut": false,
"player1_account_uuid": "019d9557-a1...",
"player1_uuid": "019d240f-...",
"player1_name": "Alice",
"player2_account_uuid": "019d9557-b2...",
"player2_uuid": "019d2410-...",
"player2_name": "Bob",
"player1_wins": 2,
"player2_wins": 1,
"draws": 0,
"draw_type": null,
"winner_uuid": "019d240f-...",
"is_bye": false,
"is_forfeit": false
}
]
}
Get all submitted decklists for a tournament. Responses include archetype-derived leader/base fields so consumers can render leader + base without a second archetype lookup.
curl https://api.swuapi.com/tournaments/67890/decklists
{
"tournament": { "melee_id": 67890, "name": "PQ Austin", ... },
"decklists": [
{
"uuid": "019d9557-...",
"melee_id": "d1e2f3a4-...",
"player_name": "Alice",
"archetype_uuid": "019d323a-...",
"archetype_name": "Darth Vader, Dark Lord of the Sith - Yellow 30",
"leader_name": "Darth Vader",
"leader_subtitle": "Dark Lord of the Sith",
"leader_set_code": "SOR",
"base_name": "Yellow 30",
"leader_collector_number": "SOR_010",
"canonical_base_collector_number": "SOR_179",
"decklist": [
{ "id": "SOR_010", "count": 1 },
{ "id": "SOR_193", "count": 3 }
]
}
]
}
List canonical players, deduplicated across multiple tournament accounts. Sorted by match count descending.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of players to return (max 200) |
offset |
integer | 0 | Number of players to skip |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
name |
string | - | Search by player name (case-insensitive partial match) |
since |
string | - | ISO 8601 timestamp. Returns only players with updated_at >= since; pairs with after for cursor sync. |
# Search for a player
curl "https://api.swuapi.com/players?name=skywalker"
{
"players": [
{
"uuid": "019d240f-...",
"name": "42Mops",
"account_count": "2",
"tournament_count": "3",
"match_count": "25",
"melee_handles": ["42Mops"]
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 1
}
}
Get a single player by canonical player UUID. Also accepts a melee.gg account identifier as fallback.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Player UUID or melee.gg account identifier |
curl https://api.swuapi.com/players/019d240f-409b-7786-9dbe-74e91e7f1a77
{
"uuid": "019d240f-409b-7786-9dbe-74e91e7f1a77",
"name": "Alice",
"account_count": "2",
"melee_handles": ["Alice"],
"accounts": [
{ "melee_id": "abc-123", "name": "Alice" },
{ "melee_id": "def-456", "name": "Alice" }
]
}
Get all matches for a player across all tournaments and accounts. Includes tournament name, tier, and canonical player IDs.
curl https://api.swuapi.com/players/019d240f-409b-7786-9dbe-74e91e7f1a77/matches
{
"player": { "uuid": "019d240f-...", "name": "Alice" },
"matches": [
{
"uuid": "019d9557-...",
"tournament_name": "PQ Austin",
"tier": "PQ",
"format": "Premier",
"round_number": 3,
"player1_uuid": "019d240f-...",
"player1_name": "Alice",
"player2_uuid": "019d2410-...",
"player2_name": "Bob",
"player1_wins": 2,
"player2_wins": 0,
"draw_type": null
}
]
}
Get all decklists submitted by a player across tournaments and accounts. Responses include archetype-derived leader/base fields.
curl https://api.swuapi.com/players/019d240f-409b-7786-9dbe-74e91e7f1a77/decklists
{
"player": { "uuid": "019d240f-...", "name": "Alice" },
"decklists": [
{
"uuid": "019d9557-...",
"melee_id": "d1e2f3a4-...",
"tournament_name": "PQ Austin",
"tier": "PQ",
"archetype_uuid": "019d323a-...",
"archetype_name": "Darth Vader, Dark Lord of the Sith - Yellow 30",
"leader_name": "Darth Vader",
"base_name": "Yellow 30",
"decklist": [ ... ]
}
]
}
List matches across all tournaments with pagination and optional filters. Each match includes a derived draw_type field so intentional draws (0-0-3) can be separated from played draws.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of matches to return (max 200) |
offset |
integer | 0 | Number of matches to skip |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
tournament |
integer | - | Filter by tournament melee_id |
account |
string | - | Filter by account ID |
since |
string | - | ISO 8601 timestamp. Returns only matches with updated_at >= since; pairs with after for cursor sync. |
# Get all matches for a tournament
curl "https://api.swuapi.com/matches?tournament=67890"
# Get all matches for an account
curl "https://api.swuapi.com/matches?account=abc-123-def"
{
"matches": [
{
"uuid": "019d9557-...",
"tournament_uuid": "019d83a7-...",
"tournament_name": "PQ Austin",
"round_number": 1,
"player1_account_uuid": "019d9557-a1...",
"player1_uuid": "019d240f-...",
"player1_name": "Alice",
"player2_account_uuid": "019d9557-b2...",
"player2_uuid": "019d2410-...",
"player2_name": "Bob",
"player1_wins": 2,
"player2_wins": 1,
"draws": 0,
"draw_type": null,
"winner_uuid": "019d240f-..."
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 24929
}
}
Get a single match by UUID.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Match UUID |
curl https://api.swuapi.com/matches/019d9557-...
{
"uuid": "019d9557-...",
"tournament_uuid": "019d83a7-...",
"tournament_name": "PQ Austin",
"round_number": 3,
"is_top_cut": false,
"player1_account_uuid": "019d9557-a1...",
"player1_uuid": "019d240f-...",
"player1_name": "Alice",
"player2_account_uuid": "019d9557-b2...",
"player2_uuid": "019d2410-...",
"player2_name": "Bob",
"player1_wins": 2,
"player2_wins": 0,
"draws": 0,
"draw_type": null,
"winner_uuid": "019d240f-...",
"is_bye": false,
"is_forfeit": false
}
List decklists across all tournaments with pagination and filters. Each row includes archetype-derived leader/base fields so downstream consumers do not need to join archetypes separately.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of decklists to return (max 200) |
offset |
integer | 0 | Number of decklists to skip |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
tournament_uuid |
string | - | Filter by tournament UUID. Preferred over tournament for new integrations — matches /standings's param naming. |
tournament |
integer | - | Filter by tournament melee_id (legacy) |
account |
string | - | Filter by account ID |
archetype |
string | - | Search by archetype name (case-insensitive partial match) |
hasCards |
boolean | - | Filter to only decklists with card data (true) |
since |
string | - | ISO 8601 timestamp. Returns only decklists with updated_at >= since; pairs with after for cursor sync. |
# Find all Darth Vader decklists
curl "https://api.swuapi.com/decklists?archetype=Vader"
# Get decklists for a specific tournament (preferred)
curl "https://api.swuapi.com/decklists?tournament_uuid=019d83a7-1155-74fd-90fe-7fe2c55135f4"
# Or by melee_id (legacy)
curl "https://api.swuapi.com/decklists?tournament=67890"
{
"decklists": [
{
"uuid": "019d9557-...",
"melee_id": "d1e2f3a4-...",
"archetype_uuid": "019d323a-...",
"archetype_name": "Darth Vader, Dark Lord of the Sith - Yellow 30",
"leader_name": "Darth Vader",
"leader_subtitle": "Dark Lord of the Sith",
"leader_set_code": "SOR",
"base_name": "Yellow 30",
"leader_collector_number": "SOR_010",
"canonical_base_collector_number": "SOR_179",
"player_name": "Alice",
"tournament_name": "PQ Austin",
"tier": "PQ",
"decklist": [
{ "id": "SOR_010", "count": 1 }
]
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 5216
}
}
Get a single decklist by its ID. Includes the full decklist plus archetype-derived leader/base fields.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
meleeId |
string | Decklist ID (UUID) |
curl https://api.swuapi.com/decklists/d1e2f3a4-5678-90ab-cdef
{
"uuid": "019d9557-...",
"melee_id": "d1e2f3a4-...",
"account_uuid": "019d9557-c54d-...",
"player_name": "Alice",
"tournament_uuid": "019d83a7-1155-...",
"archetype_uuid": "019d323a-...",
"archetype_name": "Darth Vader, Dark Lord of the Sith - Yellow 30",
"leader_name": "Darth Vader",
"leader_subtitle": "Dark Lord of the Sith",
"leader_set_code": "SOR",
"base_name": "Yellow 30",
"leader_collector_number": "SOR_010",
"canonical_base_collector_number": "SOR_179",
"decklist": [
{ "id": "SOR_010", "count": 1 },
{ "id": "SOR_193", "count": 3 }
],
"tournament_name": "PQ Austin",
"tier": "PQ",
"format": "Premier"
}
List archetypes (leader + normalized base combinations) with pagination and search. Common bases are normalized to color+HP (e.g., "Yellow30"), rare bases keep their name (e.g., "Tarkintown").
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | - | Required. Filter by format: Premier or Limited. |
limit |
integer | 20 | Number of archetypes to return (max 200) |
after |
string | - | UUID cursor for forward pagination. Pass next_cursor from the previous response. Alias: ?cursor=. |
name |
string | - | Search name or nickname (case-insensitive) |
since |
string | - | ISO 8601 timestamp. Returns only archetypes with updated_at >= since; pairs with after for cursor sync. |
curl "https://api.swuapi.com/archetypes?format=Premier"
curl "https://api.swuapi.com/archetypes?format=Premier&name=Han+Solo"
// Paginate through every Premier archetype using cursor
let cursor = null
do {
const url = `https://api.swuapi.com/archetypes?format=Premier${cursor ? `&cursor=${cursor}` : ''}`
const { archetypes, pagination } = await (await fetch(url)).json()
archetypes.forEach(a => console.log(a.name))
cursor = pagination.next_cursor
} while (cursor)
{
"archetypes": [
{
"uuid": "019d3239-22ef-76ec-b412-ac0b8def717a",
"name": "Han Solo, Worth the Risk - Energy Conversion Lab",
"nickname": "Han Solo (SHD) - Energy Conversion Lab",
"format": "Premier",
"leader_aspects": ["Cunning", "Heroism"],
"base_aspects": ["Vigilance"],
"leader_uuid": "019d3177-...",
"leader_name": "Han Solo",
"leader_subtitle": "Worth the Risk",
"leader_collector_number": "SHD_015",
"leader_image_url": "https://cdn.starwarsunlimited.com/...",
"base_group_uuid": "019d363c-...",
"base_group_name": "Energy Conversion Lab",
"canonical_base_uuid": "019d3178-...",
"canonical_base_collector_number": "SHD_101",
"canonical_base_image_url": "https://cdn.starwarsunlimited.com/...",
"decklist_count": 437
}
],
"pagination": { "next_cursor": "019d3239-22ef-76ec-b412-ac0b8def717a" }
}
Get a single archetype by UUID. Includes leader/base details, decklist count, archetype groups, and subarchetypes.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Archetype UUID |
curl https://api.swuapi.com/archetypes/019d3239-22ef-76ec-b412-ac0b8def717a
const response = await fetch(
'https://api.swuapi.com/archetypes/019d3239-22ef-76ec-b412-ac0b8def717a'
)
const archetype = await response.json()
{
"uuid": "019d3239-22ef-76ec-b412-ac0b8def717a",
"name": "Han Solo, Worth the Risk - Energy Conversion Lab",
"nickname": "Han Solo (SHD) - Energy Conversion Lab",
"format": "Premier",
"leader": {
"uuid": "019d3177-...",
"name": "Han Solo",
"subtitle": "Worth the Risk",
"collector_number": "SHD_015",
"image_url": "https://cdn.starwarsunlimited.com/...",
"aspects": ["Cunning", "Heroism"]
},
"base_group": {
"uuid": "019d363c-...",
"canonical_name": "Energy Conversion Lab",
"cards": [ { "uuid": "019d3178-...", "collector_number": "SHD_101" } ]
},
"canonical_base_card": {
"uuid": "019d3178-...",
"collector_number": "SHD_101",
"image_url": "https://cdn.starwarsunlimited.com/..."
},
"leader_aspects": ["Cunning", "Heroism"],
"base_aspects": ["Vigilance"],
"decklist_count": 437,
"archetype_groups": [ { "uuid": "019d4a12-...", "name": "Han Builds" } ],
"subarchetypes": []
}
Reverse taxonomy lookup: returns every archetype_group that contains this archetype. An archetype can belong to zero or more groups. Returns 404 if the archetype UUID doesn't exist.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Archetype UUID. |
curl https://api.swuapi.com/archetypes/019d3239-22ef-76ec-b412-ac0b8def717a/groups
{
"archetype_groups": [
{
"uuid": "019d4a12-...",
"name": "Yellow Aggro",
"description": "Yellow-based aggressive leaders running fast ground units.",
"created_at": "2026-01-15T00:00:00Z",
"updated_at": "2026-03-02T14:20:00Z"
}
]
}
Stateless compute: returns the canonical identity (name, nickname, base_group_uuid, aspects) for a given (leader, base, format) tuple. Does NOT create a row. Returns uuid: null if no archetype exists yet for the tuple. Use POST if you want find-or-create.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
leader_card_uuid | string | Yes | UUID of the leader card. |
base_card_uuid | string | Yes | UUID of the base card. |
format | string | Yes | Premier or Limited. |
curl "https://api.swuapi.com/archetypes/resolve?leader_card_uuid=019d3177-...&base_card_uuid=019d3177-...&format=Premier"
{
"uuid": "019d3239-22ef-76ec-b412-ac0b8def717a",
"name": "Han Solo, Audacious Smuggler - Yellow 30",
"nickname": "Han Solo (SOR) - Yellow 30",
"format": "Premier",
"leader_card_uuid": "019d3177-...",
"base_group_uuid": "019d363c-...",
"canonical_base_card_uuid": "019d3178-...",
"leader_aspects": ["Cunning", "Heroism"],
"base_aspects": ["Cunning"]
}
Find-or-create an archetype. Accepts either UUID-based or name-based bodies; UUIDs take precedence if both are present. Returns the archetype's UUID plus canonical identity fields, creating a new row if the (leader, base, format) tuple didn't exist. Downstream importers such as Wayfinder should prefer the UUID shape when they have card UUIDs, including Karabast preview-set archetypes that appear before tournament results exist.
Name-based input rejection. If leader_name/leader_subtitle doesn't match an is_leader=true card, or base_name doesn't match either a base_group's canonical_name or an is_base=true card, the request returns 400 (not a silent create). This is a deliberate guardrail against upstream artifacts polluting the catalog.
Request Body (UUID shape)
| Field | Type | Required | Description |
|---|---|---|---|
leader_card_uuid | string | Yes | UUID of the leader card. |
base_card_uuid | string | Yes | UUID of the base card. |
format | string | Yes | Premier or Limited. |
Request Body (name shape)
| Field | Type | Required | Description |
|---|---|---|---|
leader_name | string | Yes | Leader card name (e.g., "Han Solo"). |
leader_subtitle | string | Yes | Leader subtitle (e.g., "Audacious Smuggler"). Required to disambiguate multiple printings of the same leader name. |
base_name | string | Yes | Base group canonical name (e.g., "Yellow 30", "Force Blue") or specific rare base card name (e.g., "Aldhani Garrison"). |
format | string | Yes | Premier or Limited. |
Error Codes
| Code | Status | Meaning |
|---|---|---|
missing_param | 400 | Required field not provided. |
invalid_format | 400 | format must be Premier or Limited. |
leader_name_not_found | 400 | (name-shape) leader_name does not match any is_leader=true card. Don't retry — fix the input. |
base_name_not_found | 400 | (name-shape) base_name does not match any base_group or is_base=true card. |
leader_not_found | 404 | (UUID-shape) the given leader_card_uuid does not exist. |
base_not_found | 404 | (UUID-shape) the given base_card_uuid does not exist. |
not_a_leader | 400 | Card exists but is not flagged is_leader=true. |
not_a_base | 400 | Card exists but is not flagged is_base=true. |
# UUID-based (Wayfinder/Karabast ingest)
curl -X POST https://api.swuapi.com/archetypes/resolve \
-H "Content-Type: application/json" \
-d '{
"leader_card_uuid": "019d3177-...",
"base_card_uuid": "019d3178-...",
"format": "Premier"
}'
# Name-based fallback
curl -X POST https://api.swuapi.com/archetypes/resolve \
-H "Content-Type: application/json" \
-d '{
"leader_name": "Han Solo",
"leader_subtitle": "Audacious Smuggler",
"base_name": "Yellow 30",
"format": "Premier"
}'
{
"uuid": "019d3239-22ef-76ec-b412-ac0b8def717a",
"name": "Han Solo, Audacious Smuggler - Yellow 30",
"nickname": "Han Solo (SOR) - Yellow 30",
"format": "Premier",
"leader_card_uuid": "019d3177-...",
"base_group_uuid": "019d363c-...",
"canonical_base_card_uuid": "019d3178-...",
"leader_aspects": ["Cunning", "Heroism"],
"base_aspects": ["Cunning"]
}
Batch-reconcile archetype UUIDs against the current server state. For each input UUID, returns whether it's still active, has been merged into another archetype (with to_uuid pointing at the terminal of the merge chain), or is missing entirely. Designed for downstream caches to prune stale entries after migrations or upstream deletions.
Request Body
| Field | Type | Description |
|---|---|---|
uuids | string[] | Array of archetype UUIDs (max 1000 per request). |
curl -X POST https://api.swuapi.com/archetypes/reconcile \
-H "Content-Type: application/json" \
-d '{"uuids": ["019d3239-22ef-76ec-b412-ac0b8def717a", "019d3db5-e3d3-79e4-b339-941b02248012", "00000000-0000-7000-8000-000000000000"]}'
{
"results": [
{ "uuid": "019d3239-22ef-76ec-b412-ac0b8def717a", "status": "active" },
{ "uuid": "019d3db5-e3d3-79e4-b339-941b02248012", "status": "merged",
"to_uuid": "019d3239-22ef-76ec-b412-ac0b8def717a" },
{ "uuid": "00000000-0000-7000-8000-000000000000", "status": "missing" }
]
}
Curated meta-strategy clusters that roll multiple archetypes up under a shared label (e.g. "Blue Green Villain" covers Qira/ECL, Krennic/ECL, and Iden/ECL). Designed for higher-level meta analysis such as "Red Aggro is up 5% this week". Groups are small (typically < 100 rows) and hand-maintained.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
since | string | ISO-8601 timestamp. Returns only groups with updated_at >= since for incremental sync. Membership changes bump the parent group's updated_at. |
curl https://api.swuapi.com/archetype-groups
# Incremental sync: only rows changed since yesterday
curl "https://api.swuapi.com/archetype-groups?since=2026-04-18T00:00:00Z"
{
"archetype_groups": [
{
"uuid": "019d4a12-...",
"name": "Blue Green Villain",
"description": "Villain leaders running Green 30 + ECL bases.",
"member_count": 3,
"created_at": "2026-01-15T00:00:00Z",
"updated_at": "2026-03-02T14:20:00Z"
}
]
}
Single archetype_group with its member archetypes inline. Returns 404 if the UUID doesn't exist. Use /archetype-groups/:id/members for a richer shape that also includes subarchetypes.
curl https://api.swuapi.com/archetype-groups/019d4a12-...
{
"uuid": "019d4a12-...",
"name": "Blue Green Villain",
"description": "Villain leaders running Green 30 + ECL bases.",
"created_at": "2026-01-15T00:00:00Z",
"updated_at": "2026-03-02T14:20:00Z",
"archetypes": [
{ "uuid": "019d3239-...", "name": "Qira - Energy Conversion Lab", "nickname": "Qira ECL", "format": "Premier" }
]
}
All members of the group, split into archetypes and subarchetypes. A group can contain either or both — subarchetypes are build variants within a single archetype (e.g. "Lando Heroic" vs "Lando Yellow") that deserve their own meta slot.
Each member row includes weight and confidence as explicit nulls. Scoring columns don't exist in the schema yet; the fields are present today so the response shape stays stable when scoring lands.
curl https://api.swuapi.com/archetype-groups/019d4a12-.../members
{
"archetypes": [
{
"uuid": "019d3239-...",
"name": "Qira - Energy Conversion Lab",
"nickname": "Qira ECL",
"format": "Premier",
"weight": null,
"confidence": null
}
],
"subarchetypes": [
{
"uuid": "019d5b33-...",
"archetype_uuid": "019d3240-...",
"name": "Lando Heroic",
"description": "Yellow/Blue Heroic aspect build.",
"weight": null,
"confidence": null
}
]
}
Canonical base groupings used for normalization. Common bases collapse to color + HP (e.g. "Yellow 30" covers every yellow 30-HP base printing); rare bases keep their card name (e.g. "Tarkintown"). This is what drives archetype naming — two decklists with different "Yellow 30" printings resolve to the same archetype.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
since | string | ISO-8601 timestamp. Returns only base groups with updated_at >= since. |
curl https://api.swuapi.com/base-groups
{
"base_groups": [
{
"uuid": "019d363c-...",
"canonical_name": "Yellow 30",
"color": "Yellow",
"hp": 30,
"rarity_class": "common",
"created_at": "2025-11-01T00:00:00Z",
"updated_at": "2025-11-01T00:00:00Z"
},
{
"uuid": "019d363d-...",
"canonical_name": "Tarkintown",
"color": null,
"hp": null,
"rarity_class": "named",
"created_at": "2025-11-01T00:00:00Z",
"updated_at": "2025-11-01T00:00:00Z"
}
]
}
Single base group with its member base cards (all printings that normalize to this group). Returns 404 if the UUID doesn't exist.
curl https://api.swuapi.com/base-groups/019d363c-...
{
"uuid": "019d363c-...",
"canonical_name": "Yellow 30",
"color": "Yellow",
"hp": 30,
"rarity_class": "common",
"created_at": "2025-11-01T00:00:00Z",
"updated_at": "2025-11-01T00:00:00Z",
"cards": [
{ "uuid": "019d3178-...", "collector_number": "SOR_101", "set_code": "SOR" }
]
}
List archetypes using one base group in a specific format, ordered by decklist count descending.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Base group UUID. |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | Yes | Premier or Limited. |
curl "https://api.swuapi.com/base-groups/019d363c-.../archetypes?format=Premier"
Build variants within a single archetype, driven by scoring rules against the decklist. Each subarchetype has 0+ rules of type aspect, trait, or card; classification counts matches and picks the highest-scoring subarchetype.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO-8601. Filter by updated_at >= since. |
archetype_uuid | string | - | Only subarchetypes belonging to this parent archetype. |
limit | integer | 200 | Page size (max 1000). |
after | string | - | UUID cursor. Pass pagination.next_cursor from the previous response. |
curl https://api.swuapi.com/subarchetypes
# Only subarchetypes for one archetype
curl "https://api.swuapi.com/subarchetypes?archetype_uuid=019d3240-..."
# Incremental sync
curl "https://api.swuapi.com/subarchetypes?since=2026-04-18T00:00:00Z"
{
"subarchetypes": [
{
"uuid": "019d5b33-...",
"archetype_uuid": "019d3240-...",
"name": "Lando Heroic",
"description": "Yellow/Blue Heroic aspect build.",
"created_at": "2026-02-01T00:00:00Z",
"updated_at": "2026-02-01T00:00:00Z",
"scoring_rules": [
{ "uuid": "019d5b40-...", "rule_type": "aspect", "values": ["Heroism"] },
{ "uuid": "019d5b41-...", "rule_type": "card", "values": ["SOR_001", "SOR_002"] }
]
}
],
"pagination": { "next_cursor": null }
}
Single subarchetype with its scoring rules. Returns 404 if the UUID doesn't exist.
curl https://api.swuapi.com/subarchetypes/019d5b33-...
{
"uuid": "019d5b33-...",
"archetype_uuid": "019d3240-...",
"name": "Lando Heroic",
"description": "Yellow/Blue Heroic aspect build.",
"created_at": "2026-02-01T00:00:00Z",
"updated_at": "2026-02-01T00:00:00Z",
"scoring_rules": [
{ "uuid": "019d5b40-...", "rule_type": "aspect", "values": ["Heroism"] }
]
}
Generate a deck image (PNG) from a JSON card list or text decklist. Returns the image directly. Cards are resolved against the card database for art. Supports custom branding and card variant art.
Request Body
Send either JSON (Content-Type: application/json) or plain text decklist (Content-Type: text/plain).
JSON Fields
| Field | Type | Required | Description |
|---|---|---|---|
cards | array | * | Array of card objects (see below) |
text | string | * | Text decklist (e.g., "1 Han Solo (SOR) 017"). Use instead of cards |
title | string | No | Title text (default: leader name or "Deck") |
subtitle | string | No | Subtitle text (e.g., player name, event) |
date | string | No | Date string to display |
branding | object | No | { url: "yoursite.com" } — override default swuapi branding |
* Provide either cards or text, not both.
Card Object
| Field | Type | Description |
|---|---|---|
name | string | Card name (e.g., "Han Solo, Audacious Smuggler") |
type | string | "Leader", "Base", "Ground Unit", "Space Unit", "Event", "Upgrade" |
count | integer | Number of copies (default 1) |
variant | string | Card variant for art (e.g., "Hyperspace", "Showcase"). Falls back to Standard |
Text Decklist Format
Standard decklist format: COUNT NAME (SET) NUMBER, one card per line.
# JSON format
curl -X POST https://api.swuapi.com/deck-image \
-H "Content-Type: application/json" \
-d '{
"cards": [
{"name": "Han Solo, Audacious Smuggler", "type": "Leader", "variant": "Hyperspace"},
{"name": "Mos Eisley", "type": "Base"},
{"name": "Millennium Falcon, Piece of Junk", "type": "Space Unit", "count": 3},
{"name": "Cunning", "type": "Event", "count": 3}
],
"title": "Han Solo Aggro",
"subtitle": "by terronk"
}' --output deck.png
# Text decklist format
curl -X POST https://api.swuapi.com/deck-image \
-H "Content-Type: application/json" \
-d '{
"text": "1 Han Solo (SOR) 017\n1 Mos Eisley (JTL) 030\n3 Cunning (SOR) 203\n3 Millennium Falcon (SOR) 155",
"title": "Han Solo Aggro"
}' --output deck.png
# Plain text body
curl -X POST https://api.swuapi.com/deck-image \
-H "Content-Type: text/plain" \
-d '1 Han Solo (SOR) 017
1 Mos Eisley (JTL) 030
3 Cunning (SOR) 203' --output deck.png
const response = await fetch('https://api.swuapi.com/deck-image', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
cards: [...],
title: 'Han Solo Aggro',
branding: { url: 'mysite.com' } // optional
})
})
const blob = await response.blob()
// Display or download the PNG image
Generate a deck image from a saved decklist. Returns PNG directly. Includes player name and tournament as subtitle. Embed in <img> tags or share directly.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
meleeId | string | Decklist ID (UUID) |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
brandUrl | string | Override branding URL |
brandName | string | Override branding name |
# Download deck image for a specific decklist
curl https://api.swuapi.com/deck-image/decklist/2261b229-5a8a-4ced-8b75-b3e200bca054 --output deck.png
# With custom branding
curl "https://api.swuapi.com/deck-image/decklist/2261b229?brandUrl=mysite.com" --output deck.png
<!-- Embed directly in HTML -->
<img src="https://api.swuapi.com/deck-image/decklist/2261b229-5a8a-4ced-8b75-b3e200bca054" />
List all meta eras. A meta era is a competitive period defined by available card pool and ban list. Set releases and mid-set bans create distinct sub-eras.
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | all | Filter by format: premiere or limited |
curl https://api.swuapi.com/metas
curl "https://api.swuapi.com/metas?format=premiere"
{
"metas": [
{
"id": "JTL-pre-ban",
"name": "Jump to Lightspeed (pre-ban)",
"set": "JTL",
"setName": "Jump to Lightspeed",
"format": "premiere",
"start": "2025-03-14",
"end": "2025-04-11",
"isCurrent": false,
"bans": []
},
{
"id": "JTL-post-ban",
"name": "Jump to Lightspeed (post-ban)",
"set": "JTL",
"setName": "Jump to Lightspeed",
"format": "premiere",
"start": "2025-04-11",
"end": "2025-07-11",
"isCurrent": false,
"bans": [
{ "card": "Jango Fett, Concealing the Conspiracy", "cardId": "TWI_016", "action": "suspended", "effectiveDate": "2025-04-11", "format": "premiere" }
]
}
]
}
Get the current active meta era.
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | premiere | Format: premiere or limited |
curl https://api.swuapi.com/metas/current
Get a specific meta era by ID (e.g., JTL-post-ban, SOR, TWI-limited).
curl https://api.swuapi.com/metas/JTL-post-ban
Get metas formatted for UI dropdowns. By default, when a set has sub-eras (pre-ban/post-ban), only the sub-eras are returned (not the full set entry). Sorted newest first.
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | premiere | Format: premiere or limited |
includeFullSet |
boolean | false | Include full-set entries alongside sub-eras |
curl https://api.swuapi.com/metas/dropdown
{
"options": [
{ "id": "LAW", "name": "A Lawless Time", "isCurrent": true },
{ "id": "SEC", "name": "Secrets of Power", "isCurrent": false },
{ "id": "LOF-post-ban", "name": "Legends of the Force (post-ban)", "isCurrent": false },
{ "id": "LOF-pre-ban", "name": "Legends of the Force (pre-ban)", "isCurrent": false }
]
}
List all ban/suspension events.
curl https://api.swuapi.com/metas/bans
List all set release dates.
curl https://api.swuapi.com/metas/sets
List melee.gg accounts for incremental sync. An account is a single login; a canonical player can own multiple accounts. Use ?since= to pull only rows whose updated_at advanced since your last poll.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO 8601 timestamp. Returns only accounts with updated_at >= since. |
player_uuid | string | - | Filter to accounts belonging to one canonical player. |
team_tag | string | - | Filter to accounts whose handle matches an approved team prefix. |
after | string | - | Cursor — pair with next_cursor from the previous page. |
limit | integer | 200 | Page size. Max 1000. |
curl "https://api.swuapi.com/accounts?since=2026-03-01T00:00:00Z&limit=500"
Get one melee.gg account by UUID.
curl https://api.swuapi.com/accounts/019d9557-c54d-...
List tournament venues for incremental sync. Each row carries city/state/country plus lat/lng when known.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO 8601 timestamp. Returns only venues with updated_at >= since. |
after | string | - | Cursor — pair with next_cursor from the previous page. |
limit | integer | 200 | Page size. Max 1000. |
curl "https://api.swuapi.com/venues?since=2026-03-01T00:00:00Z"
Get one canonical venue by UUID.
curl https://api.swuapi.com/venues/019d81dd-...
Flat list of final standings across tournaments, for incremental sync. Distinct from GET /tournaments/:uuid/standings?round=N, which is the live per-round view for a single event. The no_decklist_submitted field lives here: true means the source confirmed the player did not submit a decklist, not that swuapi failed to scrape one.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO 8601 timestamp. Returns only standings with updated_at >= since. |
tournament_uuid | string | - | Limit to one tournament. |
player_uuid | string | - | Limit to one canonical player. |
after | string | - | Cursor — pair with next_cursor from the previous page. |
limit | integer | 200 | Page size. Max 1000. |
curl "https://api.swuapi.com/standings?since=2026-03-01T00:00:00Z&limit=500"
{
"standings": [
{
"uuid": "019d9557-...",
"tournament_uuid": "019d83a7-...",
"player_uuid": "019d240f-...",
"rank": 1,
"final_placement": 1,
"points": 24,
"no_decklist_submitted": false,
"decklist_uuid": "019d9557-...",
"updated_at": "2026-03-01T00:00:00.000Z"
}
],
"pagination": { "next_cursor": null }
}
See Incremental Sync for the shared since/after/limit contract used across list endpoints.
Get one final-standing row by UUID.
curl https://api.swuapi.com/standings/019d9557-...
List approved team prefixes used to tag melee.gg account handles.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
all | boolean | false | When true, include inactive prefixes. |
curl https://api.swuapi.com/team-prefixes
Paginated SWUDB L1 decklist feed for downstream consumers. This is source-layer data and uses offset pagination, not L2 UUID cursor pagination.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | - | ISO 8601 timestamp. When present, returns rows whose last_fetched_at is newer than this timestamp, ordered by last_fetched_at ASC. |
limit | integer | 200 | Page size. Max 500. |
offset | integer | 0 | Offset for pagination. |
curl "https://api.swuapi.com/swudb/decklists?since=2026-03-01T00:00:00Z&limit=200"
Get the merge log for sync consumers. When entities are merged (duplicate archetypes, players, accounts, tournaments, venues, etc.), this endpoint reports what was merged and when. Consumers should poll this periodically and re-point their local references. Covered entity_type values: tournament, player, account, decklist, match, standing, venue, archetype.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since |
string | (required) | ISO 8601 timestamp — only return merges after this time |
entity_type |
string | - | Filter to one entity type (e.g. player, tournament, venue). |
Contract: card merges never emit. cards.uuid is write-once; upstream card removal is a delete, not a merge. Consumers should not expect entity_type = "card".
curl "https://api.swuapi.com/merges?since=2026-03-01T00:00:00Z"
{
"merges": [
{
"entity_type": "archetype",
"from_uuid": "019d3239-...",
"to_uuid": "019d3240-...",
"merged_at": "2026-03-20T15:30:00.000Z"
},
{
"entity_type": "player",
"from_uuid": "019d240f-...",
"to_uuid": "019d2410-...",
"merged_at": "2026-03-20T16:00:00.000Z"
}
]
}
Deletion tombstone stream for sync consumers. Poll this alongside /merges so downstream mirrors can remove entities that swuapi intentionally deleted, such as rejected phantom tournaments.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | 2020-01-01T00:00:00Z | Only return deletions after this timestamp. |
entity_type | string | - | Filter to one entity type. |
curl "https://api.swuapi.com/deletions?since=2026-03-01T00:00:00Z"
{
"deletions": [
{
"entity_type": "tournament",
"swuapi_uuid": "019d83a7-...",
"melee_id": 418419,
"reason": "rejected_phantom_tournament",
"deleted_at": "2026-03-20T16:00:00.000Z"
}
]
}
Data-quality findings stream for consumers. Open findings describe known upstream or swuapi data issues such as phantom events, stale live tournaments, unresolved archetypes, or missing tournament artifacts.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | open | open, accepted, resolved, or all. |
kind | string | - | Filter to one finding kind. |
severity | string | - | Filter by severity. |
source | string | - | Filter by source system. |
since | string | - | ISO 8601 timestamp. Enables UUID cursor pagination for incremental sync. |
before | string | - | Optional stale cutoff. |
after | string | - | UUID cursor. Returned as next_cursor only when since or after is present. |
limit | integer | 100 | Page size. Max 500. |
curl "https://api.swuapi.com/findings?status=open&since=2026-03-01T00:00:00Z"
{
"findings": [
{
"uuid": "019d9a44-...",
"kind": "phantom_melee_event",
"severity": "high",
"status": "open",
"dedupe_key": "melee:418419",
"last_seen_at": "2026-03-20T16:00:00.000Z"
}
],
"next_cursor": null
}
Card Object
Complete reference for all card fields.
Card Identifiers
Each card has several identifiers:
| Field | Type | Description | Unique? |
|---|---|---|---|
uuid | UUID | Stable unique identifier (ours) | Yes |
external_id | integer | Source API integer ID | Yes |
collector_number | string | Printed card code (SET_NUMBER format) | No — variants share the same number |
external_uid | string | Source API string UID | Yes |
Examples:
| Card | uuid | external_id | collector_number | variant_type |
|---|---|---|---|---|
| Standard Luke | 59e4... | 5 | SOR_005 | Standard |
| Foil Luke | a3b2... | 9745 | SOR_005 | Standard Foil |
| Hyperspace Luke | f1c7... | 981 | SOR_278 | Hyperspace |
Use uuid as the primary identifier. collector_number is not unique — foil and non-foil share the same printed number. Hyperspace cards have their own printed numbers.
Fields
| Field | Type | Description |
|---|---|---|
uuid | UUID | Stable unique identifier |
external_id | int | Source API integer ID (unique per variant) |
collector_number | string | Printed card code (SET_NUMBER format, e.g., SOR_005) |
external_uid | string | Source API string UID |
name | string | Card name |
subtitle | string | Card subtitle |
setCode | string | Set code (e.g., SOR) |
cardNumber | string | Number within set |
serialCode | string | Full serial code |
type | string | Leader, Unit, Event, Upgrade, Base |
type2 | string | Secondary type (e.g., Leader Unit) |
rarity | string | Common, Uncommon, Rare, Legendary, Special |
cost | int | Resource cost |
power | int | Attack power |
hp | int | Health points |
upgradePower | int | Power modifier (upgrades) |
upgradeHp | int | HP modifier (upgrades) |
arena | string | Ground or Space |
aspects | array | Aspect names |
aspectDuplicates | array | Duplicate aspects |
traits | array | Trait names (Rebel, Jedi, etc.) |
keywords | array | Keywords (Ambush, Sentinel, etc.) |
text | string | Card ability text |
deployBox | string | Leader deploy ability |
epicAction | string | Epic action text |
rules | string | Additional rules |
variantType | string | Standard, Hyperspace, Standard Foil, Hyperspace Foil, Showcase, Prerelease Promo, etc. |
isUnique | bool | Whether card is unique |
isLeader | bool | Is a leader card |
isBase | bool | Is a base card |
frontImageUrl | string | Front card image URL |
backImageUrl | string | Back card image URL |
thumbnailUrl | string | Thumbnail image URL |
artFrontHorizontal | bool | Front art orientation |
artBackHorizontal | bool | Back art orientation |
artist | string | Card artist name |
variants | array | strapiIds of variant cards |
variantOf | int | strapiId of original (if variant) |
reprints | array | strapiIds of reprint cards |
reprintOf | int | strapiId of original (if reprint) |
Set Codes
Known set codes and their full names.
| Code | Name |
|---|---|
SOR | Spark of Rebellion |
SHD | Shadows of the Galaxy |
TWI | Twilight of the Republic |
JTL | Jump to Lightspeed |
LOF | Legends of the Force |
SEC | Secrets of Power |
LAW | A Lawless Time |
Meta Eras
Competitive periods defined by card pool and ban list. Set releases create new eras; mid-set bans split an era into pre-ban and post-ban sub-eras.
| ID | Name | Start | End |
|---|---|---|---|
SOR | Spark of Rebellion | 2024-03-08 | 2024-07-12 |
SHD | Shadows of the Galaxy | 2024-07-12 | 2024-11-09 |
TWI | Twilight of the Republic | 2024-11-09 | 2025-03-14 |
JTL-pre-ban | Jump to Lightspeed (pre-ban) | 2025-03-14 | 2025-04-11 |
JTL-post-ban | Jump to Lightspeed (post-ban) | 2025-04-11 | 2025-07-11 |
LOF-pre-ban | Legends of the Force (pre-ban) | 2025-07-11 | 2025-09-22 |
LOF-post-ban | Legends of the Force (post-ban) | 2025-09-22 | 2025-11-07 |
SEC | Secrets of Power | 2025-11-07 | 2026-03-13 |
LAW | A Lawless Time | 2026-03-13 | (current) |
Ban Events
| Card | Action | Date |
|---|---|---|
| Jango Fett, Concealing the Conspiracy | Suspended | 2025-04-11 |
| Triple Dark Raid | Suspended | 2025-04-11 |
| DJ, Blatant Thief | Suspended | 2025-04-11 |
| Force Throw | Suspended | 2025-09-22 |
Standings
Standings placement fields are sourced from melee.gg's last standings tab for each tournament — usually labeled "Finals" (sometimes a round number for swiss-only events). rank = 1 is the tournament champion when the stored snapshot includes bracket placement. Match and game record fields are recomputed from canonical L2 matches because melee.gg's standings tabs report per-round records, not full-event W-L-D.
Historical tournaments backfilled before April 2026 were persisted with swiss-only standings (rank-1 = top swiss seed, not champion). Those are being re-scraped to the last-tab format; until that completes you may see a mix of the two. The tournaments.winner_player_uuid field is maintained from standings.rank = 1, so it reflects whichever snapshot is currently stored.
final_placement is the canonical tournament finish, derived from the bracket on every pipeline run:
- 1 — bracket champion (winner of the finals match).
- 2 — runner-up.
- 3, 4 — semifinal losers, tiebroken by swiss rank ASC.
- 5–8 — quarterfinal losers, tiebroken by swiss rank ASC.
- 9–16, etc. — earlier elimination rounds, same tiebreak.
- top_cut_size + 1 … — swiss-only players, ordered by swiss rank ASC.
- NULL — bracket incomplete (any top-cut match without a reported winner).
For pure-swiss tournaments (no top-cut matches), final_placement = rank. Invariant per tournament: MAX(final_placement) <= COUNT(standings). Prefer final_placement over rank for placement-aware queries; rank reflects melee's raw published order and is kept as-is for backwards compatibility.
GET /standings?since=— flat incremental-sync feed of final standings (one row per player per tournament).GET /tournaments/:id/standings?round=N— live per-round view while an event is running (only exists for tournaments observed by the live scraper).tournaments.winner_player_uuid— denormalized champion, cheap to query without joining standings.
Tournament Tiers
Competitive event tiers in Star Wars: Unlimited organized play.
| Code | Name | Description |
|---|---|---|
PQ | Planetary Qualifier | Local-level competitive events (official) |
SQ | Sector Qualifier | Regional-level competitive events (official) |
RQ | Regional Qualifier | Major regional events (official) |
GC | Galactic Championship | Top-tier championship events (official) |
LCQ | Last Chance Qualifier | Last-chance entry events into championships (official) |
SS | Store Showdown | Casual store-level events (official, Asmodee-branded) |
INV | Invitational | Invitation-only competitive events (unofficial). Retired — now stored as COM. |
COM | Community | Community-run competitive events (unofficial) |
CAS | Casual Side Event | Sealed/Draft/Carbonite/On-Demand/Spotlight side events held alongside qualifier tournaments. Not official competition. |
Aspect Colors
SWU has four gameplay aspects, each with a canonical color. Heroism and Villainy are alignment aspects that modify brightness.
| Aspect | Color Name | Hex | Sample |
|---|---|---|---|
| Aggression | Red | #A83632 |
|
| Command | Green | #338D5A |
|
| Cunning | Yellow | #C5A14F |
|
| Vigilance | Blue | #4B86AA |
Alignment Modifiers
| Alignment | Effect | Use |
|---|---|---|
| Heroism | Lighter, slightly desaturated | Hero leaders (Han Solo, Sabine, Luke, etc.) |
| Villainy | Darker, more saturated | Villain leaders (Vader, Palpatine, Boba Fett, etc.) |
Base Naming Convention
| Base HP | Rarity | Naming | Example |
|---|---|---|---|
| 30 | Common | Color 30 | Red 30, Yellow 30 |
| 28 | Common | Force Color | Force Blue, Force Red |
| 27 | Common | Splash Color | Splash Green, Splash Yellow |
| varies | Rare/Special | Card name | Tarkintown, Data Vault, ECL |
Archetype Nicknames
Each archetype has a short nickname: FirstName (SET) BaseNick. Titles/ranks are stripped to get the character's name. (SET) is only included when multiple distinct leaders share the same first name.
| Full Name | Nickname | Rule |
|---|---|---|
| Han Solo, Audacious Smuggler - Red 30 | Han Red 30 | Simple first name + base color + HP |
| Darth Vader, Dark Lord of the Sith - Force Blue | Vader (SOR) Force Blue | Title stripped, (SET) for disambiguation |
| Grand Admiral Thrawn, Patient and Insightful - Data Vault | Thrawn (SOR) DV | Multi-word title stripped, base abbreviated |
| Grand Moff Tarkin, Oversector Governor - Tarkintown | Tarkin TT | SW title stripped, base abbreviated |
| Moff Gideon, Formidable Commander - Red 30 | Gideon Red 30 | SW title stripped |
| Grand Inquisitor, Hunting the Jedi - Tarkintown | GI TT | Hardcoded nickname override |
| The Mandalorian, Sworn To The Creed - Red 30 | Mando Red 30 | Special case |
| Boba Fett, Any Methods Necessary - Energy Conversion Lab | Boba (JTL) ECL | Multiple Bobas need (SET) |
Base Abbreviations in Nicknames
| Base | Nickname |
|---|---|
| Tarkintown | TT |
| Energy Conversion Lab | ECL |
| Data Vault | DV |
| Lake Country | Lake |
| Red 30 / Blue 30 / etc. | Red 30 / Blue 30 / etc. (HP preserved) |
| Force Blue / Splash Green / etc. | Unchanged |
| Other rare bases | Full name |