Skip to content

Error Handling

TCG API uses standard HTTP status codes and returns structured error responses.

{
"error": {
"message": "Human-readable error description",
"code": "MACHINE_READABLE_CODE"
}
}
CodeMeaning
200Success
201Created (registration, key creation)
400Bad request (missing params, invalid input)
401Unauthorized (missing or invalid auth)
403Forbidden (tier restriction)
404Not found
409Conflict (duplicate email)
429Rate limit exceeded
500Internal server error
// 401 — No API key provided
{ "error": { "message": "API key required", "code": "API_KEY_REQUIRED" } }
// 401 — Invalid key
{ "error": { "message": "Invalid or deactivated API key", "code": "INVALID_API_KEY" } }
// 401 — Session expired
{ "error": { "message": "Not authenticated", "code": "UNAUTHORIZED" } }
// 429 — Daily quota exceeded
{ "error": { "message": "Daily rate limit exceeded. Resets at midnight UTC.", "code": "RATE_LIMIT_EXCEEDED" } }
// 403 — Endpoint requires higher tier
{ "error": { "message": "This endpoint requires a Pro subscription", "code": "TIER_REQUIRED" } }
// 400 — Missing search query
{ "error": { "message": "Query parameter 'q' is required (min 2 characters)", "code": "HTTP_400" } }
// 400 — Invalid request
{ "error": { "message": "Invalid JSON", "code": "HTTP_400" } }
async function fetchCard(id) {
const resp = await fetch(`https://api.tcgapi.dev/v1/cards/${id}`, {
headers: { 'X-API-Key': API_KEY },
});
if (!resp.ok) {
const err = await resp.json();
switch (resp.status) {
case 401: throw new Error('Invalid API key');
case 403: throw new Error('Upgrade required: ' + err.error.message);
case 404: return null; // Card not found
case 429: throw new Error('Rate limited — try again tomorrow');
default: throw new Error(err.error.message);
}
}
return resp.json();
}
  • 429 responses: Don’t retry until the daily reset (midnight UTC)
  • 5xx responses: Retry with exponential backoff (1s, 2s, 4s)
  • 4xx responses: Fix the request, don’t retry as-is