Repository navigation
API guide
| URL | Purpose |
|---|---|
/api/docs |
Interactive FastAPI documentation |
/api/openapi.json |
OpenAPI schema |
/api/health |
API version and maintenance state |
Use the schema from your running version for exact wire contracts. API endpoints and API models provide a source-derived reference for this documented revision.
Most routes require an authenticated user. /api/users and /api/admin/* require an administrator. Catalog IDs and printing IDs are local database identifiers; obtain them from the catalog APIs before changing stock.
POST JSON to /api/auth/login with username, password, and mode: "token". The response contains access_token, refresh_token, token_type: "bearer" and expires_in. Use Authorization: Bearer <access token> on subsequent requests.
For local scripts, this standard-library Python example prompts for credentials and avoids embedding them in source:
import getpass
import json
import urllib.request
base = input("Server URL: ").rstrip("/")
username = input("Username: ")
password = getpass.getpass("Password: ")
body = json.dumps({"username": username, "password": password, "mode": "token"}).encode()
request = urllib.request.Request(
base + "/api/auth/login", data=body,
headers={"Content-Type": "application/json"}, method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
session = json.load(response)
request = urllib.request.Request(
base + "/api/collection",
headers={"Authorization": "Bearer " + session["access_token"]},
)
with urllib.request.urlopen(request, timeout=30) as response:
collection = json.load(response)
print("Collection rows:", collection["total"])Use HTTPS for credentials outside a trusted local setup. This example is for local accounts; it is not a substitute for the OIDC mobile/browser flow.
POST /api/auth/refresh with a refresh token in token mode. Rotation returns a replacement pair; retain the new refresh token. Reusing an older rotated token outside the short concurrency grace period revokes the token family. POST /api/auth/logout with the refresh token to end the session.
The default access lifetime is one hour and refresh lifetime is 90 days, sliding on rotation. Password changes, account disabling and server signing-key changes can end sessions earlier.
Login with mode: "cookie" sets HttpOnly session cookies and returns the user. Unsafe cookie-authenticated requests must include X-TCG-CSRF: 1. Token-mode bearer requests do not need that CSRF header. Browser refresh/logout can use their refresh cookie; see the schema for optional body fields.
The refresh cookie is scoped under /api/auth; preserve the actual cookie attributes rather than treating it as a general JavaScript-readable token.
-
GET /api/gamesfor game IDs, available variants, filters and source capabilities. -
GET /api/games/{game_id}/setsfor local sets. -
GET /api/cards?game=mtg&q=...for logical cards. -
GET /api/cards/{card_id}or its/printingsroute for exact printing IDs. -
POST /api/collection/adjustto change a confirmed variant.
Do not invent a printing ID from its collector number.
After resolving a real printing ID, the adjustment body is:
{
"printing_id": 123,
"finish": "nonfoil",
"condition": "NM",
"language": "en",
"delta": 1,
"source": "web"
}123 is a placeholder and must be replaced. finish must be valid for that printing/game. The response includes the resulting item and a transaction ID. A negative delta removes copies. An absolute PATCH can set quantity, notes or manual price; manual_price: null restores automatic prices and notes: null clears notes.
CSV import uses multipart field file, query mode=add|set, and optional dry_run=true. Even an HTTP 200 response can contain row errors; inspect errors and imported. Do not set a JSON Content-Type for multipart data.
The scan endpoint accepts JSON OCR lines, not images. Each line can include text, left, top, width and height, with coordinates normalized to 0–1. Maximum input: 200 lines, 300 characters per text. Its status is found, not_found, other_game or not_a_card. Candidate printings do not themselves change stock.
Collection pages use items, total, page and page_size; defaults are page 1 and size 50, up to 500 collection rows. Catalog pages also use items with the same pagination metadata, up to 200 cards. Some other list routes have their own shape. Repeat query keys for lists, for example color=W&color=G or attr=types:Creature&attr=rarity:rare with a selected game. Encode spaces and non-ASCII query values normally.
| Status | Meaning in common paths |
|---|---|
| 400 | Invalid operation or malformed input handled by the route |
| 401 | Missing, expired or ended session |
| 403 | Missing role, disabled local login, or missing CSRF header |
| 404 | Missing user/card/printing/item/game |
| 409 | Stock conflict, duplicate account/job or protected SSO edit |
| 413 | Body or CSV too large |
| 422 | Request schema validation |
| 429 | Authentication rate limit; honor Retry-After |
| 500 | Unexpected backend error; inspect server logs |
| 503 | Load-triggered maintenance for ordinary users |
Standard route errors normally use detail; FastAPI validation errors can carry a structured list. Avoid retrying non-idempotent stock additions automatically after an ambiguous network failure: first inspect the resulting collection/history to prevent duplicates. There is no documented general idempotency-key mechanism.
Home · Troubleshooting · Documentation baseline · Source
Documented baseline: server 0.20.1 / Android 0.11.0. Game data and trademarks belong to their respective owners.
Collectors
- Getting started
- Catalog and card pages
- Managing your collection
- Prices and valuation
- CSV import and export
- Account and preferences
- Android guide
- Supported games and sources
- FAQ
Server administration
- Docker installation
- Configuration reference
- Reverse proxy and HTTPS
- Single sign on
- User administration
- Synchronization
- Data checks
- Images and symbols
- Operations
- Backup and restore
- Updates and migrations
- Troubleshooting
Technical reference