# pickthetcg · intents.md

pickthetcg is a **trade board for card games**. Pick a card and say what you want to do with it, **buy**, **sell**
or **trade**, as a plain intents.md document on the shared feed at intentsmd.com. Two collections today: the full
**Vibes** TCG library (Pudgy Penguins) and a curated set of **Pokémon** grails. No account, no custody, no
payments: it matches intents and never handles a card. Everything below is public and keyless.

## Find a card: `GET /cards.json`

Both collections in one static file (about 360 KB).

```
GET https://pickthetcg.com/cards.json
```

```json
{
  "collections": [
    {
      "id": "vibes", "name": "Vibes", "game": "Vibes TCG · Pudgy Penguins", "source": "vibes.game",
      "imgBase": "https://ocg-card-catalog.s3.us-west-2.amazonaws.com/Spoiler_Previews/", "ext": ".png",
      "cardUrl": "https://www.vibes.game/spoiler/",
      "cards": [["A Drop in Attention", "ADropinAttention"], ["Absent-Minded Penguin", "AbsentMindedPenguin"], "..."]
    },
    {
      "id": "pokemon", "name": "Pokémon", "game": "Pokémon TCG", "source": "pokemontcg.io",
      "cards": [["Umbreon ex", "sv8pt5-161", "https://images.pokemontcg.io/sv8pt5/161.png", "Prismatic Evolutions", "Special Illustration Rare"], "..."]
    }
  ]
}
```

| collection | rows | row shape |
|---|---|---|
| `vibes` | 570, the full card library | `[name, slug]`. Art is `https://pickthetcg.com` + `imgBase + slug + ext` (`imgBase` is `/card/`); the card's page on vibes.game is `cardUrl + slug`. |
| `pokemon` | 4,906: 3,225 grails (ultra, illustration, secret and similar rares) across 121 sets, plus every vintage card from Base Set to Skyridge that the price guide covers | `[name, cardId, imageUrl, set, rarity]`. `cardId` is the pokemontcg.io id; its page is `https://pokemontcg.io/cards/{cardId}`, except for the 111 cards whose `imageUrl` is on `images.scrydex.com` (pokemontcg.io has no page for those). |

The Pokémon list is **not** every Pokémon card. The board also takes any other card through "Add your own card":
an intent that names the card (and optionally its set) without a `cardId`.

There is no search endpoint. Filter the file yourself; the board filters this same file in the browser.

## Card art

| URL | what it is |
|---|---|
| `https://pickthetcg.com/card/{slug}.png` | a Vibes card's art, served from our domain and cached. A slug with characters other than letters and digits is `404`; a slug that isn't in the library fails upstream (`502`). |
| the row's `imageUrl` | a Pokémon card's art (`images.pokemontcg.io` or `images.scrydex.com`) |

## Intents: `buy`, `sell` and `trade`

An intent for one card is posted to the shared intents.md feed. This is the same call the board's **Post to the
feed** button makes: no key, CORS open.

```
POST https://intentsmd.com/api/intents
Content-Type: application/json

{
  "verb": "want",
  "title": "Buy A Drop in Attention (Vibes TCG)",
  "category": "🃏 vibes tcg",
  "price": "20 USD",
  "contact": "mailto:you@example.com",
  "region": "world",
  "level": "l0",
  "body": "Open to fair offers.\n\n**A Drop in Attention** — Vibes TCG · Pudgy Penguins\nCard: https://www.vibes.game/spoiler/ADropinAttention"
}
```

A Pokémon trade:

```
{
  "verb": "offer",
  "title": "Trade Umbreon ex (Pokémon TCG)",
  "category": "🃏 pokemon tcg",
  "price": "Espeon ex from the same set",
  "contact": "mailto:you@example.com",
  "region": "world",
  "level": "l0",
  "body": "Open to trade offers.\n\n**Umbreon ex** — Pokémon TCG · Prismatic Evolutions · Special Illustration Rare\nCard: https://pokemontcg.io/cards/sv8pt5-161"
}
```

| field | for a card |
|---|---|
| `verb` | `want` to buy; `offer` to sell **or** trade (the title says which) |
| `title` | `{Buy\|Sell\|Trade} {card name} (Vibes TCG)` or `… (Pokémon TCG)` |
| `category` | exactly `🃏 vibes tcg` or `🃏 pokemon tcg`: the board and the feed filter find each collection's intents by it |
| `price` | free text, as the person typed it: a budget (buy), an ask (sell), or what they want in return (trade), e.g. `"20 USD"`. No currency is added. Optional. |
| `contact` | where the person can be reached: a `mailto:` address or an `https://` URL. The feed accepts a post without one; the board always sends one. |
| `region`, `level` | `world` and `l0` (an unsigned post) |
| `body` | Markdown, up to 5,000 characters. The board sends the person's note, then the card line as above. The `Card:` link is left out for "add your own" cards and for Pokémon cards with scrydex art. Its default notes are "Open to fair offers." (buy), "Serious buyers welcome." (sell) and "Open to trade offers." (trade). |

**Response** `201` (abridged)

```json
{ "id": "…", "url": "/i/…",
  "intent": { "verb": "want", "title": "Buy A Drop in Attention (Vibes TCG)", "category": "🃏 vibes tcg", "price": "20 USD",
              "region": "world", "level": "l0", "status": "active", "interest": 0, "…": "…" } }
```

The intent is now public at `https://intentsmd.com/i/{id}`, served as `text/markdown`: a few header lines
(`type`, `title`, `published`, `ask`, `contact`, …), then the `body`.

**Errors** are `{ "error": "…" }` in plain words: `400` for a bad `verb`, a `title` under 3 characters, a `contact`
that isn't `mailto:` or `https://`, or a body that isn't JSON; `413` over 16 KB; `429` past **10 posts an hour**
per IP. Leave out the `website` field (it is a spam trap and must be empty).

## Read the card intents

```
GET https://intentsmd.com/api/intents?cat=%F0%9F%83%8F%20vibes%20tcg&sort=latest&limit=12
GET https://intentsmd.com/api/intents?cat=%F0%9F%83%8F%20pokemon%20tcg&sort=latest&limit=12
```

`cat` is `🃏 vibes tcg` or `🃏 pokemon tcg`, URL-encoded. Returns `{ "intents": [...] }`, each with `id`, `verb`,
`title`, `price`, `region`, `level`, `status`, `interest` and `created_at` (milliseconds). `sort` is `latest`
(default), `popular` or `trust`; `limit` goes up to 50; `q` filters by text in the title. The list leaves out
`contact`: read it from the intent's own doc at `https://intentsmd.com/i/{id}`. This is what the board's "Recently
pitched" strip shows for each tab.

MCP clients can read the same feed at `https://intentsmd.com/mcp` (Streamable HTTP, read-only): `search_intents`
with `category: "🃏 vibes tcg"` or `"🃏 pokemon tcg"`, and `list_categories`.

## The document the board builds

Before posting, the board shows the person this intents.md document and lets them copy or download it
(`intent-{buy|sell|trade}-{slug or cardId}.md`). It is built in the browser; the site does not serve these files.
A Vibes card:

```
---
intent: buy
asset: A Drop in Attention
game: Vibes TCG · Pudgy Penguins
budget: 20 USD
contact: mailto:you@example.com
card: https://www.vibes.game/spoiler/ADropinAttention
posted: 2026-09-29
---

# Buy — A Drop in Attention

**Game:** Vibes TCG · Pudgy Penguins

Open to fair offers.
```

A Pokémon card:

```
---
intent: trade
asset: Umbreon ex
game: Pokémon TCG
set: Prismatic Evolutions
rarity: Special Illustration Rare
card_id: sv8pt5-161
looking_for: Espeon ex from the same set
contact: mailto:you@example.com
posted: 2026-09-29
---

# Trade — Umbreon ex

**Game:** Pokémon TCG  ·  Prismatic Evolutions  ·  Special Illustration Rare

Open to trade offers.
```

The price line's key follows the side: `budget` (buy), `ask` (sell), `looking_for` (trade). An "add your own" card
has no `card_id` or `rarity`, and its game line reads `Pokémon TCG (card described by the poster)`. Values that
would break YAML (a name like `Type: Null`) are quoted.

## Share page

`https://pickthetcg.com/s/{slug or cardId}?side=buy|sell|trade&i={intentId}` is an HTML page for people and
social cards: it shows the card and links to `https://intentsmd.com/i/{intentId}`. "Add your own" cards have no
share page; the board shares the intentsmd.com link directly.

## Data and honesty

- **Vibes** card names come from the public card library at vibes.game, captured read-only. **Pokémon** data and
  images come from pokemontcg.io and scrydex.com. `/cards.json` is a snapshot, rebuilt by hand.
- pickthetcg has **no price, inventory or ownership data**. It doesn't know who has a card or what it sells for,
  except through intents people post.
- An intent is a statement, not an order. Nothing is escrowed or shipped; the two sides settle between themselves.
- Posts are unsigned (`level: l0`): the feed doesn't verify who posted them.
- Card names and art belong to their games. pickthetcg is an independent trade-listing tool, not affiliated with or
  endorsed by Orange Cap Games / vibes.game, pokemontcg.io, scrydex.com, or Nintendo · Creatures · GAME FREAK ·
  The Pokémon Company.

See also: [/agents.md](/agents.md) · [/llms.txt](/llms.txt) · https://pickthetcg.com · the protocol: https://intentsmd.org
