Skip to content
Crypto-only, prepaid. Top up a balance and we draw from it monthly — nothing is ever charged automatically.
tcggraph

Errors

Errors are always JSON, always carry a stable machine-readable code, and never leak internal detail.

Error shape

Any non-2xx response has an error object. The code is stable and safe to switch on; the message is for humans and may change.

{
  "error": {
    "code": "invalid_request",
    "message": "Unknown game \"pokemon-tcg\".",
    "details": {
      "field": "game",
      "allowed": ["pokemon", "magic-the-gathering", "one-piece"]
    }
  }
}

Status codes

StatusCodeMeaning
400invalid_requestA parameter failed validation. The response names the offending field.
401unauthenticatedMissing or malformed API key.
402no_active_planThe account has no plan attached. Choose one to open the API.
402balance_emptyThe account balance will not cover this call. Top up to resume.
403forbiddenThe key is valid but the plan does not include this resource.
404not_foundNo card, set or game matches the identifier.
409conflictThe webhook or export already exists.
422unprocessable_queryThe GraphQL query exceeded depth or complexity limits.
429rate_limitedQuota exhausted. Check the Retry-After header.
500internal_errorSomething broke on our side. It is already paging someone.

Retrying safely

Retry 429 and 5xx. Never retry 400, 401, 403 or 404 — the result will not change. A 402 means the account cannot pay for the call — either no plan is attached (no_active_plan) or the balance is empty (balance_empty). Neither resolves on its own, so alert a human rather than backing off. Honour Retry-After when it is present.

async function withRetry(fn, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    const res = await fn();
    if (res.status !== 429 && res.status < 500) return res;

    // Honour Retry-After when present; otherwise back off exponentially.
    const after = Number(res.headers.get("Retry-After"));
    const waitMs = Number.isFinite(after) ? after * 1000 : 2 ** i * 250;
    await new Promise((r) => setTimeout(r, waitMs));
  }
  throw new Error("Exhausted retries");
}

GraphQL errors

GraphQL follows the spec: transport errors use HTTP status codes, and resolver errors return 200 with an errors array. Each entry carries the same code under extensions, so you can share error handling between both interfaces.