# prereq API

Public JSON API for the prereq Grand Archive card database.

**Base URL:** `https://prereq.cards/api`

This documentation is also available as [raw markdown](/api/docs.md) at `/api/docs.md`, suitable for feeding to LLMs or other automated tools.

All endpoints return JSON. Errors use `{"error": "..."}` format. CORS is enabled for all origins.

---

## Authentication and usage

None. There is no authentication, no API keys, no tokens, no rate limits.

Please set a descriptive `User-Agent` HTTP header so we can identify your project's requests in the logs and reach you if something goes wrong — give it a project name, URL, version number, and/or email address. Example:

```
User-Agent: my-deckbuilder/1.0 (contact@example.com)
```

**Usage policy:** Don't be a dick. 
No, seriously. Don't make me have to ban UAs or run a UA whitelist. Don't make me have to implement real auth and a usage policy and ratelimiting.

Please think about how you're structuring your app, and try to minimize API requests. For example, cache responses where possible. Then, consider that a few thousand extra db requests a day won't be something I notice in the usage logs. A few billion however, and it might well be a problem. If you're uncertain, you can get in touch and ask, email address is on the main prereq about page. 

---

## Attribution policy

If using our API lets you provide a useful service to your users, please:
* give us credit by name and logo, and link them to http://prereq.cards

Please use the .svg on the front page as the canonical logo source. Our favicon is cropped heavily and not appropriate for most contexts.

In your own about page would be fine, or next to the feature -- eg, if you have a deep-query card finder with prereq-compatible syntax, right under that could well be a good place to credit us by name, logo, and link. 

---

## Endpoints

### GET /api/version

Returns API version info.

```bash
curl https://prereq.cards/api/version
```

[Try it →](https://prereq.cards/api/version)

```json
{"version": "1", "name": "prereq"}
```

### GET /api/status

Returns the latest set, total unique cards, and total editions (printings).

```bash
curl https://prereq.cards/api/status
```

[Try it →](https://prereq.cards/api/status)

```json
{
  "latest_set": "Mercurial Heart",
  "latest_set_code": "MRC",
  "latest_release_date": "2025-01-24",
  "total_cards": 1885,
  "total_editions": 3494
}
```

`total_cards` counts unique cards (by `card_uuid`). `total_editions` counts individual printings — the same card printed in multiple sets counts once per printing.

### GET /api/search?q=...

Search for cards using the [prereq query syntax](/help).

The notable thing about this endpoint, and about prereq query syntax, is that users can type it to build complex queries in text, and for experienced users, this is fast and fluid. Consider if you're exposing this distinct feature. 

(If you're just fetching lists of cards by their details, please use https://api.gatcg.com/cards/search instead, as documented at https://api-docs.gatcg.com/endpoints/multiple-cards -- it has the advantages of being canonical, comprehensive, guranteed to be up to date etc, due to being hosted and developed by the official first-party Weebs of the Shore team.)

| Parameter   | Default | Description |
|-------------|---------|-------------|
| `q`         | *(required)* | Search query |
| `page`      | 1       | Page number |
| `page_size` | 50      | Results per page (max 100) |
| `sort`      | name    | Sort field: `name`, `rarity`, `cost`, `collector_number`, `set`, `element`, `type`, `price`, `winrate`, `date` |
| `order`     | asc     | Sort direction: `asc` or `desc` |

```bash
curl 'https://prereq.cards/api/search?q=e%3Afire+t%3Aregalia&page_size=5'
```

[Try it →](https://prereq.cards/api/search?q=e%3Afire+t%3Aregalia&page_size=5)

```json
{
  "count": 12,
  "page": 1,
  "total_pages": 3,
  "cards": [
    {
      "edition_slug": "blazing-jewel-doa-1st",
      "name": "Blazing Jewel",
      "edition_uuid": "abc123...",
      "card_uuid": "def456..."
    }
  ]
}
```

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `count` | integer | Total matching results across all pages |
| `page` | integer | Current page number |
| `total_pages` | integer | Total number of pages |
| `cards` | array | Array of search hits |
| `cards[].edition_slug` | string | URL-safe slug for this printing (use in `/api/card/{slug}`) |
| `cards[].name` | string | Card name |
| `cards[].edition_uuid` | string | Unique identifier for this printing |
| `cards[].card_uuid` | string | Shared identifier across all printings of the same card |

Query syntax errors return HTTP 400 with an `error` field describing what went wrong.

### GET /api/card/{edition_slug}

Full card data for a single printing.

```bash
curl https://prereq.cards/api/card/lorraine-wandering-warrior-doa-1st
```

[Try it →](https://prereq.cards/api/card/lorraine-wandering-warrior-doa-1st)

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `edition_uuid` | string | Unique identifier for this printing |
| `edition_slug` | string | URL-safe slug for this printing |
| `card_uuid` | string | Shared identifier across all printings of the same card |
| `name` | string | Card name |
| `classes` | string[] | Card classes, e.g. `["WARRIOR"]` |
| `types` | string[] | Card types, e.g. `["CHAMPION"]` |
| `subtypes` | string[] | Card subtypes, e.g. `["WARRIOR", "HUMAN"]` |
| `elements` | string[] | Elements, e.g. `["FIRE"]`, `["WATER", "WIND"]` |
| `cost` | object | Cost object (see below) |
| `cost.type` | string | `"memory"`, `"reserve"`, or `"none"` |
| `cost.value` | string? | Cost value: `"0"`, `"3"`, `"X"`, or `null` for no cost |
| `durability` | int? | Regalia/item durability |
| `level` | int? | Champion level |
| `life` | int? | Champion life |
| `power` | int? | Attack power |
| `speed` | bool? | Whether the card is fast (true) or slow (false/null) |
| `effect_text` | string? | Card effect as plain text (for searching, display without markup) |
| `effect_html` | string? | Card effect as HTML with bolding, paragraphs, etc. |
| `effect_reminder` | string? | Reminder text only (keyword explanations), plain text |
| `flavor_text` | string? | Flavor text |
| `illustrator` | string? | Artist name |
| `collector_number` | string? | Collector number within the set |
| `rarity` | int? | Rarity: 1=Common, 2=Uncommon, 3=Rare, 4=Super Rare, 5=Ultra Rare, 6=Promo Rare, 7=CSR, 8=CUR, 9=CPR |
| `set_code` | string? | Set code, e.g. `"DOA-1ST"` |
| `set_name` | string? | Set name, e.g. `"Dawn of Ashes First Edition"` |
| `images` | object | Image URLs (see [Card images](#card-images) section) |
| `images.index_jpg` | string? | 500x700 JPG from the official GA Index |
| `images.avif` | string? | 300px-wide AVIF from prereq CDN |
| `images.thumbnail` | string? | 180px-wide AVIF thumbnail, cropped to card top |
| `is_flip_card` | bool | Whether this card has a back face |
| `back_name` | string? | Back face name (flip cards only) |
| `back_classes` | string[] | Back face classes |
| `back_types` | string[] | Back face types |
| `back_subtypes` | string[] | Back face subtypes |
| `back_elements` | string[] | Back face elements |
| `back_cost` | object | Back face cost (same structure as `cost`) |
| `back_durability` | int? | Back face durability |
| `back_level` | int? | Back face level |
| `back_life` | int? | Back face life |
| `back_power` | int? | Back face power |
| `back_speed` | bool? | Back face speed |
| `back_effect_text` | string? | Back face effect as plain text |
| `back_effect_html` | string? | Back face effect as HTML |
| `back_effect_reminder` | string? | Back face reminder text |
| `back_flavor_text` | string? | Back face flavor text |
| `back_illustrator` | string? | Back face illustrator |
| `back_images` | object? | Back face image URLs (same structure as `images`; null if not a flip card) |
| `release_date` | string? | Release date |
| `language` | string? | Language code, e.g. `"EN"` |

The `cost` object matches the official GA API format. A card has at most one cost type — memory or reserve, never both. Examples:

- Memory cost 3: `{"type": "memory", "value": "3"}`
- Reserve cost X: `{"type": "reserve", "value": "X"}`
- No cost (champions, etc.): `{"type": "none", "value": null}`

Returns 404 if the edition slug doesn't match any card.

### GET /api/card/{edition_slug}/offers

Price offers for a card from tracked stores.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `region`  | *(all)* | Filter by region: `NZ`, `AU`, or `GLOBAL` |

```bash
curl https://prereq.cards/api/card/lorraine-wandering-warrior-doa-1st/offers
curl 'https://prereq.cards/api/card/lorraine-wandering-warrior-doa-1st/offers?region=NZ'
```

[Try it →](https://prereq.cards/api/card/lorraine-wandering-warrior-doa-1st/offers)

```json
{
  "edition_slug": "lorraine-wandering-warrior-doa-1st",
  "offers": [
    {
      "store_name": "Card Merchant Hamilton",
      "store_slug": "cm-hamilton",
      "region_code": "NZ",
      "price_cents": 50,
      "currency": "NZD",
      "condition": "NM",
      "finish": "normal",
      "quantity": 4,
      "product_url": "https://cardmerchanthamilton.co.nz/...",
      "scraped_at": "2026-02-26T08:00:00+00:00"
    }
  ]
}
```

**Response fields:**

| Field | Type | Description |
|-------|------|-------------|
| `edition_slug` | string | The card's edition slug |
| `offers` | array | Array of price offers, sorted by price ascending |
| `offers[].store_name` | string | Store display name |
| `offers[].store_slug` | string | Store identifier |
| `offers[].region_code` | string | `"NZ"`, `"AU"`, or `"GLOBAL"` |
| `offers[].price_cents` | integer | Price in minor currency units (cents) |
| `offers[].currency` | string | Currency code, e.g. `"NZD"`, `"AUD"` |
| `offers[].condition` | string? | Card condition, e.g. `"NM"` |
| `offers[].finish` | string? | Card finish, e.g. `"normal"`, `"foil"` |
| `offers[].quantity` | int? | Available quantity (null if unknown) |
| `offers[].product_url` | string? | Direct link to the store listing |
| `offers[].scraped_at` | string? | ISO 8601 timestamp of when this offer was last confirmed — updates every scrape even if the price hasn't changed |

Returns 404 if the card doesn't exist. An empty `offers` array means the card exists but has no tracked offers.

---

## Card images

There are three image sources available.

### Index JPGs (official GA API)

The `images.index_jpg` field points to the official 500x700 JPG hosted by the GA Index. These are the canonical card images, suitable for most use cases. They're the highest publically available quality, and widely compatible. They're basically guranteed to be available so long as the cards are up on the Index. For further documentation, see the docs at https://api-docs.gatcg.com/endpoints/images which will tell you how to hit up the  https://api.gatcg.com/cards/images/{filename} endpoint. 

```
https://api.gatcg.com/cards/images/{edition_uuid}.jpg
```

### prereq CDN — AVIF (fast, compact)

The `images.avif` field points to 300px-wide AVIF images on prereq's CDN (Cloudflare R2). These are re-encoded from the originals for fast loading in modern browsers, and served from a Cloudflare CDN. If you want your app to go fast, are serving modern browsers, and can trade off some quality, these may be appropriate, and are what prereq uses. Note that they may not be available immediately when new cards are added, as the image processing happens offline on my laptop whenever I notice that there's new cards.

```
https://cdn.prereq.cards/{set_code}/{filename}.avif
```

### prereq CDN — Thumbnails (tiny)

The `images.thumbnail` field points to 180px-wide AVIF thumbnails. These are heavily compressed, and cropped to approximately the top 1/7th of the card (showing the name, element, cost, and top of the illustration). They can get down to low single-digit kilobytes per image, which saves bandwidth and loading time when showing a lot of card images at once. Same benefits and caveats as the large prereq images apply. 

```
https://cdn.prereq.cards/{set_code}/{filename}-s.avif
```

### Hotlinking

prereq's image CDN runs on Cloudflare R2, which has **no egress fees**. Hotlinking cdn.prereq.cards images costs us nothing, and we do not consider this use of our API. So you don't need to credit us for this usecase, and as for usage amount, Cloudflare can handle any traffic you can generate. 

---

## Query syntax

The `q` parameter accepts the full prereq query language. See [/help](/help) for the complete reference.

Examples, drawn from the help page:

- [`silvie`](/api/search?q=silvie) — name searches
- [`e:fire t:regalia`](/api/search?q=e%3Afire+t%3Aregalia) — fire element regalias
- [`e:luxem fx:"class bonus" t:tamer`](/api/search?q=e%3Aluxem+fx%3A%22class+bonus%22+t%3Atamer) — luxem cards with class-bonus tamer effects
- [`!e:a pow>5`](/api/search?q=%21e%3Aa+pow%3E5) — non-advanced element cards with power above 5
- [`fx:"deal ? damage"`](/api/search?q=fx%3A%22deal+%3F+damage%22) — cards dealing damage (single-character wildcard)
- [`c:3`](/api/search?q=c%3A3) — cards costing exactly 3 memory or reserve
- [`e:water OR e:norm t:aethercharge`](/api/search?q=e%3Awater+OR+e%3Anorm+t%3Aaethercharge) — water or norm element aethercharges
- [`i:Taki`](/api/search?q=i%3ATaki) — cards illustrated by Taki
