Skip to main content

API Endpoints

This page provides a complete reference of all available API endpoints.

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

Error Responses​

These error responses are shared across endpoints. Each endpoint's own Error Responses table lists the statuses it declares and links back here.

Payment Required​

Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). The API key is preserved; access resumes automatically once the subscription is active again. Emitted by the EnsureActiveSubscription middleware (issue #2038).

{
"errors": [
{
"status": "402",
"code": "SUBSCRIPTION_REQUIRED",
"title": "Payment Required",
"detail": "An active subscription is required to access this endpoint. Subscribe or update your billing to restore access; your API key is preserved and access resumes automatically once your subscription is active."
}
]
}

Bad Request​

Bad Request — the query string contains a parameter this endpoint does not accept, or the requested page size exceeds the maximum of 100. Unrecognized parameters are rejected rather than ignored, so a misspelled filter can never silently return the full unfiltered collection (issue #2305). One error object is returned per offending parameter, each naming it in source.parameter, and the detail lists every parameter the endpoint does accept.

{
"errors": [
{
"status": "400",
"code": "INVALID_PARAMETER",
"title": "Unknown query parameter",
"detail": "The query parameter 'name' is not supported by this endpoint. Accepted parameters are: first_name, full_name, include, last_name, limit, order_by, page, per_page, sort.",
"source": {
"parameter": "name"
}
}
]
}

Too Many Requests​

Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Every published endpoint except GET /health and POST /webhooks/stripe is throttled by the api limiter, whose quota is chosen per caller: anonymous requests (no bearer token) get the anonymous tier, and an authenticated request gets, in precedence order, its OAuth client's per-client rate_limit override, the internal-caller pool if the client row is flagged is_internal, or the default authenticated tier. See config/ratelimiting.php for the current values. A few public endpoints stack a tighter named per-IP limiter on top of the api bucket (signup, verification resend, invite validation), so they can return a 429 well before the api quota is spent — those operations describe the extra limit in their own description.

{
"errors": [
{
"status": "429",
"code": "TOO-MANY-REQUESTS",
"title": "Too many requests.",
"detail": "You have sent too many requests in a given amount of time. Please retry after a short delay."
}
]
}

Unprocessable Entity​

Unprocessable Entity — the request document failed validation. One error object is returned per offending field per rule, each naming the field with an RFC 6901 JSON Pointer in source.pointer (bare field names are rooted under /data/attributes/). The detail carries the human-readable validation message.

{
"errors": [
{
"status": "422",
"code": "VALIDATION-FAILED",
"title": "Validation failed",
"detail": "The name field is required.",
"source": {
"pointer": "/data/attributes/name"
}
},
{
"status": "422",
"code": "VALIDATION-FAILED",
"title": "Validation failed",
"detail": "The selected year id is invalid.",
"source": {
"pointer": "/data/attributes/year_id"
}
}
]
}

Health​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /health​

Liveness/readiness healthcheck (infrastructure)

Infrastructure healthcheck for load balancers and uptime monitors. Returns 200 when the database and cache are reachable, or 503 when a dependency check fails. Unauthenticated, unthrottled, and excluded from API usage logging. Not a public API feature. The checks.billing key is advisory only: it reports degraded when billing or lifecycle-email configuration is incomplete and never affects the status code.

Authentication: Public — no API token required.

Example Request​

curl -X GET "https://api.tradingcardapi.com/health" \
-H "Accept: application/json"

Example Response​

{
"status": "ok",
"version": "0.2.84",
"checks": {
"database": "ok",
"cache": "ok",
"billing": "ok"
}
}

Error Responses​

StatusDescription
503At least one dependency check failed; the app is not ready to serve traffic

Internal​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /internal/analytics/customer-usage​

Per-customer API usage (internal)

Returns one row per customer (a user with a billing account or a live API key) with the request count and last-request time over an inclusive UTC date range. Customers with no requests in range are included with request_count 0. request_count counts requests made with the customer's API key (credential_type api_key); requests_by_credential reports every credential type. Usage cannot be attributed per key, so each row reports the customer's current key metadata. The usage log keeps 30 days; meta.oldest_log_at marks the oldest retained row. Requires the 'internal' OAuth scope.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
fromstringNoFirst day of the range (Y-m-d, UTC). Defaults to 6 days before to.
tostringNoLast day of the range (Y-m-d, UTC), inclusive. Defaults to today. The span may not exceed 31 days.
userstringNoRestrict to one customer by user id
paying_onlybooleanNoOnly customers whose subscription status is active (trials excluded)

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/analytics/customer-usage" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "customer-usage",
"id": "string",
"attributes": {}
}
],
"meta": {}
}

Error Responses​

StatusDescription
401Unauthenticated
403Missing the 'internal' scope
422Invalid date, range, user, or paying_only parameter
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /internal/analytics/sales-readiness​

Sales readiness report (internal)

Returns the analyze:sales-readiness data-coverage report. Requires the 'internal' OAuth scope. Use format=json (default) for the structured payload or format=table for the rendered text table.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
formatstringNoOutput format: json (default) or table
yearsintegerNoNumber of most recent years to include in year coverage (must be a positive integer)
monthsintegerNoNumber of most recent months for the update-cadence window (positive integer)

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/analytics/sales-readiness" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated
403Missing the 'internal' scope
422Invalid format, years, or months parameter
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /internal/audit-logs​

List audit log events (internal)

Retrieve audit log events with optional filtering by entity, event type, and date range. Defaults to last 30 days when no date filters are provided. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[auditable_type]stringNoFilter by entity type (e.g. set, card, player, team)
filter[auditable_id]stringNoFilter by entity UUID
filter[event_type]stringNoFilter by event type
filter[start_date]stringNoFilter events on or after this date (ISO 8601)
filter[end_date]stringNoFilter events on or before this date (ISO 8601)
per_pageintegerNoNumber of results per page (default 50, max 500)
pageintegerNoPage number

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/audit-logs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "audit_logs",
"id": 12345,
"attributes": {
"event_type": "agent_spawned",
"auditable_type": "set",
"auditable_id": "string",
"agent_id": "agent-abc-123",
"data": {},
"created_at": "string"
}
}
]
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /internal/audit-logs​

Create an audit log event (internal)

Record a new audit log event. Supports polymorphic association with any entity. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"audit_logs"
data.attributesobjectNoNo
data.attributes.event_typestringYesNo"agent_spawned"
data.attributes.auditable_typestringNoYes"set"
data.attributes.auditable_idstring (uuid)NoYes"550e8400-e29b-41d4-a716-446655440000"
data.attributes.agent_idstringNoYes"agent-abc-123"
data.attributes.dataobjectNoYes{"step":"populate","status":"started"}

Example Request​

curl -X POST "https://api.tradingcardapi.com/internal/audit-logs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"audit_logs","attributes":{"event_type":"agent_spawned","auditable_type":"set","auditable_id":"550e8400-e29b-41d4-a716-446655440000","agent_id":"agent-abc-123","data":{"step":"populate","status":"started"}}}}'

Example Response​

{
"data": {
"type": "audit_logs",
"id": 12345,
"attributes": {
"event_type": "agent_spawned",
"auditable_type": "set",
"auditable_id": "string",
"agent_id": "agent-abc-123",
"data": {},
"created_at": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
403Forbidden - missing the internal scope
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /internal/card-batches​

Upsert a batch of cards by client-supplied UUID (internal)

Idempotently upserts a batch of cards keyed on client-generated UUIDs: a row whose id is unknown is created, a row whose id already exists is updated, and a re-send of an unchanged batch is a no-op rather than a duplicate. Rows are written one transaction each, so a single bad row fails in isolation and is reported in results instead of aborting the batch. Batches at or under the sync threshold (config api.card_batch.sync_threshold) are processed inline and answered 200 with the full per-row result set; larger batches are queued and answered 202 with a job_id to poll via GET /internal/card-batches/{job_id}. Batch upserts do NOT trigger automatic parallel-card propagation — the caller is expected to supply its parallels explicitly with derived ids. Set meta.propagate to true to opt back in. Internal endpoint: requires the internal OAuth scope.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataarray of objectYesNoCard resource objects. Each requires a client-generated uuid id.
data[].typestringYesNo"cards"
data[].idstring (uuid)YesNo
data[].attributesobjectNoNo
data[].relationshipsobjectNoNo
metaobjectNoNo
meta.propagatebooleanNoNoAllow automatic parallel-card propagation for these rows.

Example Request​

curl -X POST "https://api.tradingcardapi.com/internal/card-batches" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":[{"type":"cards","id":"string","attributes":{},"relationships":{}}],"meta":{"propagate":false}}'

Example Response​

{
"status": "completed",
"job_id": null,
"total": 1,
"created": 1,
"updated": 0,
"failed": 0,
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "created",
"restored": null,
"error": null
}
]
}

Error Responses​

StatusDescription
401Unauthorized
403Missing the required internal OAuth scope
422Validation error
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /internal/card-batches/{job_id}​

Poll the status of an async card-batch upsert (internal)

Returns the current status of a queued card-batch upsert. The job_id comes from the 202 response of POST /internal/card-batches. Results are retained for 24 hours after completion. Internal endpoint: requires the internal OAuth scope.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
job_idstringYesJob UUID returned by the async card-batch request

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/card-batches/{job_id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"status": "completed",
"job_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"total": 1,
"created": 1,
"updated": 0,
"failed": 0,
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "created",
"restored": null,
"error": null
}
]
}

Error Responses​

StatusDescription
401Unauthorized
403Missing the required internal OAuth scope
404Batch job not found or expired
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /internal/invites​

List signup invites (internal)

Lists issued invites with their label, pinned email, use counts, expiry and revocation state. Internal endpoint: requires the internal OAuth scope.

The plaintext code is NEVER returned here — it is surfaced exactly once at issuance and only its SHA-256 hash is stored.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/invites" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated
403Missing the internal OAuth scope
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /internal/invites​

Issue a signup invite (internal)

Mints a new invite code and returns its plaintext EXACTLY ONCE — only the SHA-256 hash is persisted, so the code cannot be retrieved afterward. Internal endpoint: requires the internal OAuth scope.

All attributes are optional; an empty body issues a single-use, unpinned invite with the configured default TTL. Supply max_uses for a cohort code, email to pin the invite to one address, and expires_at: null for an invite that never expires.

The code attribute seeds a caller-supplied plaintext instead of minting one. It exists for the cutover from the marketing site's single shared code, so links already in a cohort's hands keep working when enforcement deploys.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"invites"
data.attributesobjectNoNo
data.attributes.labelstringNoYes
data.attributes.emailstring (email)NoYes
data.attributes.max_usesintegerNoNo1
data.attributes.expires_atstring (date-time)NoYes
data.attributes.codestringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/internal/invites" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"invites","attributes":{"label":"string","email":"string","max_uses":1,"expires_at":"string","code":"string"}}}'

Error Responses​

StatusDescription
401Unauthenticated
403Missing the internal OAuth scope
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /internal/sets/{set}/todos​

List the workflow todos for a set (internal)

Returns the set's workflow todos ordered by sort_order. Returns an empty collection when the set exists but has no workflow initialized. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the parent set

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/sets/{set}/todos" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "set_todos",
"id": "string",
"attributes": {
"step": "fetch",
"status": "in_progress",
"sort_order": 1,
"started_at": "string",
"completed_at": "string",
"completed_by": "admin",
"notes": "string",
"created_at": "string",
"updated_at": "string"
}
}
]
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Set not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /internal/sets/{set}/todos​

Create a workflow todo for a set (internal)

Create a new workflow todo on the set's workflow. The todo is bound to the set's existing workflow; the set must already have one. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the parent set

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"set_todos"
data.attributesobjectNoNo
data.attributes.stepstringYesNo"fetch"
data.attributes.statusstringYesNo"pending"
data.attributes.sort_orderintegerNoYes
data.attributes.notesstringNoYes
data.attributes.completed_bystringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/internal/sets/{set}/todos" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"set_todos","attributes":{"step":"fetch","status":"pending"}}}'

Example Response​

{
"data": {
"type": "set_todos",
"id": "string",
"attributes": {
"step": "fetch",
"status": "in_progress",
"sort_order": 1,
"started_at": "string",
"completed_at": "string",
"completed_by": "admin",
"notes": "string",
"created_at": "string",
"updated_at": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Set or workflow not found
409A todo for this step already exists on the workflow (unique_workflow_step constraint)
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /internal/sets/{set}/todos/{todo}​

Get a single workflow todo for a set (internal)

Returns a single todo scoped to the parent set. A todo from a different set returns 404. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the parent set
todostringYesUUID of the set todo

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/sets/{set}/todos/{todo}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "set_todos",
"id": "string",
"attributes": {
"step": "fetch",
"status": "in_progress",
"sort_order": 1,
"started_at": "string",
"completed_at": "string",
"completed_by": "admin",
"notes": "string",
"created_at": "string",
"updated_at": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Todo not found for this set
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /internal/sets/{set}/todos/{todo}​

Delete a workflow todo for a set (internal)

Delete a todo scoped to the parent set. A todo from a different set returns 404. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the parent set
todostringYesUUID of the set todo to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/internal/sets/{set}/todos/{todo}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Todo not found for this set
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /internal/sets/{set}/todos/{todo}​

Update a set todo step status (internal)

Transition a workflow step. Enrichment steps skip ordering; others need prior completion. The todo is scoped to the parent set; a todo from a different set returns 404. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the parent set
todostringYesUUID of the set todo to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"set_todos"
data.attributesobjectNoNo
data.attributes.statusstringYesNo"in_progress"
data.attributes.notesstringNoYes
data.attributes.completed_bystringNoYes
data.attributes.issues_foundbooleanNoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/internal/sets/{set}/todos/{todo}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"set_todos","attributes":{"status":"in_progress"}}}'

Example Response​

{
"data": {
"type": "set_todos",
"id": "string",
"attributes": {
"step": "fetch",
"status": "in_progress",
"sort_order": 1,
"started_at": "string",
"completed_at": "string",
"completed_by": "admin",
"notes": "string",
"created_at": "string",
"updated_at": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Todo not found for this set
422Validation error or dependency not met
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /internal/sets/{set}/workflow​

Get the workflow state for a set (internal)

Returns the workflow record and its todos for the given set. Returns {"workflow": null} (200) when the set exists but has no workflow initialized. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesSet UUID

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/sets/{set}/workflow" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"workflow": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"set_id": "661f9511-f30c-52e5-b827-557766551111",
"priority": 1,
"current_step": "fetch",
"todos": [
{
"id": "772a0622-a41d-43f6-c938-668877662222",
"step": "discover_sources",
"status": "completed",
"sort_order": 1,
"started_at": "2024-03-15T09:00:00+00:00",
"completed_at": "2024-03-15T09:15:00+00:00",
"notes": null
},
{
"id": "883b1733-b52e-44a7-d049-779988773333",
"step": "fetch",
"status": "in_progress",
"sort_order": 2,
"started_at": "2024-03-15T09:20:00+00:00",
"completed_at": null,
"notes": "Retrying after transient 502 from source."
}
],
"created_at": "2024-03-15T08:00:00+00:00",
"updated_at": "2024-03-15T10:30:00+00:00"
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Set not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /internal/actionable-sets​

Get sets that are actionable for a given workflow step (internal)

Returns sets where the given step matches the requested status (default: pending). For pipeline steps with pending status, all prior steps must be completed or skipped. Enrichment steps bypass this requirement. Use status=review to find sets needing human intervention. Each row includes the current todo_id (for PATCH operations) and notes (the review reason when status=review). Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
stepstringYesWorkflow step (discover_sources, fetch, parse, populate, validate, cleanup, publish, audit)
statusstringNoFilter by todo status (default: pending). Use 'review' to find sets needing human intervention.
limitintegerNoMaximum number of results to return (1–100, default 25)
prioritystringNoPriority filter: 'current' (current year), 'backlog' (prior years), or 'all' (default)
genre_idstringNoFilter by genre UUID
yearstringNoFilter by year name (e.g. '2025', '2025-26')

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/actionable-sets" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"todo_id": "string",
"set_id": "string",
"set_name": "string",
"genre": "string",
"year": "string",
"step": "string",
"priority": 0,
"card_count": 0,
"has_sources": false,
"notes": "string",
"updated_at": "2025-01-15T13:45:30+00:00"
}
],
"meta": {
"total": 0,
"full_total": 0,
"step": "string",
"status": "string",
"priority_filter": "string"
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error
503Service unavailable — query timed out

GET /internal/actionable-sets/count​

Count sets that are actionable for a given workflow step (internal)

Returns the unpaginated count of sets that are actionable for the given step, using the exact same filters as GET /internal/actionable-sets (step, status, priority, genre_id, year) but without materializing the row page or the per-row card_count / has_sources subqueries. The returned count is consistent with that endpoint's full_total for identical filters. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
stepstringYesWorkflow step (discover_sources, fetch, parse, populate, validate, cleanup, publish, audit)
statusstringNoFilter by todo status (default: pending). Use 'review' to find sets needing human intervention.
prioritystringNoPriority filter: 'current' (current year), 'backlog' (prior years), or 'all' (default)
genre_idstringNoFilter by genre UUID
yearstringNoFilter by year name (e.g. '2025', '2025-26')
limitintegerNoAccepted for request-shape parity with GET /internal/actionable-sets but ignored: this endpoint returns an unpaginated count, so no row cap applies. Still validated (integer, 1-100) — an out-of-range value yields 422.

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/actionable-sets/count" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"count": 0,
"meta": {
"step": "string",
"status": "string",
"priority_filter": "string"
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error
503Service unavailable — query timed out

POST /internal/todo-initialization-jobs​

Bulk-initialize workflow todos for pre-existing sets (internal)

Initializes workflow todos for sets that have no existing workflow. Sets with existing workflows or published status are counted as skipped. When more than 100 sets would be processed, the operation is dispatched as a background job. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
set_idsarray of stringNoNoSpecific set UUIDs to initialize. Mutually exclusive with all_draft.
all_draftbooleanNoNoInitialize all draft sets without existing workflows.
genre_idstring (uuid)NoNoFilter by genre (only valid with all_draft).
yearstringNoNoFilter by year name, e.g. '2025' (only valid with all_draft).

Example Request​

curl -X POST "https://api.tradingcardapi.com/internal/todo-initialization-jobs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"set_ids":["string"],"all_draft":false,"genre_id":"string","year":"string"}'

Example Response​

{
"initialized": 0,
"skipped": 0,
"errors": [
{}
],
"job_id": "string",
"resolved_count": 0,
"meta": {
"total_draft_sets": 0,
"draft_with_workflow": 0,
"draft_without_workflow": 0
}
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /internal/todo-initialization-jobs/{job_id}​

Poll the status of an async bulk-initialize job (internal)

Returns the current status of a background bulk-initialize job. The job_id is obtained from the 202 response of POST /internal/todo-initialization-jobs. Results are retained for 24 hours after job completion. Internal endpoint: requires the internal OAuth scope (#1557).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
job_idstringYesJob UUID returned by the async bulk-initialize request

Example Request​

curl -X GET "https://api.tradingcardapi.com/internal/todo-initialization-jobs/{job_id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"status": "completed",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"initialized": 42,
"skipped": 3,
"errors": [],
"resolved_count": 45,
"meta": null
}

Error Responses​

StatusDescription
401Unauthorized
403Forbidden - missing the internal scope
404Job not found or expired
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

Webhooks​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

POST /webhooks/stripe​

Stripe webhook receiver (infrastructure)

Receives Stripe webhook events. Unauthenticated — the Stripe-Signature header verified against the configured signing secret is the authentication. Returns 200 on accepted (including duplicate and unknown event types) and 400 on signature verification failure. Not a public API feature.

Authentication: Public — no API token required.

Example Request​

curl -X POST "https://api.tradingcardapi.com/webhooks/stripe" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
400Signature verification failed or payload malformed

Authentication​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/user/api-key​

Get the authenticated user's API key (masked)

Returns masked metadata for the authenticated end user's single opaque API key. Never returns the plaintext key. If no key exists yet, data is null.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/user/api-key" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not read its owner's API-key metadata
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/user/api-key​

Regenerate the authenticated user's API key

Revokes the user's existing API key (if any) and issues a new opaque tc_live_ key. Returns the plaintext key exactly once, alongside masked metadata. The previous key stops authenticating immediately.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/user/api-key" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not rotate its owner's API key
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

DELETE /v1/user/api-key​

Revoke the authenticated user's API key

Revokes the user's existing opaque tc_live_ key (if any) without minting a replacement. The key stops authenticating immediately. Idempotent: a no-op 204 when the user has no live key. To rotate the key instead, POST the same path.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/user/api-key" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not revoke its owner's API key
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/invites/validate​

Validate a signup invite code (v1)

Reports whether an invite code may currently be used to create an account. Public (no authentication) so the marketing site's signup page can check the link a visitor arrived on before rendering a form.

This endpoint CONSUMES NOTHING and reserves nothing: a valid verdict means the code is live and had a use left at the moment of the check, not that a use — or a founding slot — is held for the caller. Enforcement happens again at POST /v1/signup.

Rejections carry a distinguishable code: invite_invalid (unknown, revoked, or pinned to a different address), invite_expired (410, renewable), or invite_exhausted (every use spent). The code must be sent in the JSON body; a code in the query string is ignored, since a query string is recorded by proxies and travels onward in Referer. Throttled by throttle:invite-validate per IP and per code so the endpoint is not a brute-force oracle.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"invite-validations"
data.attributesobjectNoNo
data.attributes.codestringYesNo"FOUNDING-2026"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/invites/validate" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"invite-validations","attributes":{"code":"FOUNDING-2026"}}}'

Error Responses​

StatusDescription
410Invite code has expired
422Invite code is missing, unknown, revoked, or fully used
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/me​

Get the authenticated user (v1)

Returns the currently authenticated user as a JSON:API resource exposing name, email, company, and the plan / subscription status / trial end mirrored from the user's billing account (null when the user has no billing account).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/me" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "users",
"id": "9b1c1e2a-3f4d-4a5b-8c6d-7e8f9a0b1c2d",
"attributes": {
"name": "Jane Doe",
"email": "[email protected]",
"company": "Acme Corp",
"plan": "pro_monthly",
"subscription_status": "active",
"trial_ends_at": "2026-07-15T00:00:00+00:00"
}
}
}

Error Responses​

StatusDescription
401Unauthenticated
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

DELETE /v1/me​

Delete the authenticated user's account and associated data (v1)

Irreversibly deletes the authenticated user's own account (issue #1979). Requires an interactive first-party session (a Passport personal access token is rejected with 401 at the authentication layer; an opaque tc_ data key with 403 by the session gate) and an explicit confirmation body { "data": { "confirm": true } }. Revokes the user's API keys and OAuth tokens, cancels the Stripe subscription, removes the Loops contact, then anonymizes the user's PII and soft-deletes the account. Billing/invoice financial records are retained (unlinked) per the documented retention policy.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectYesNo
data.confirmbooleanYesNotrue

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/me" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"confirm":true}}'

Example Response​

{
"data": {
"type": "users",
"id": "9b1c1e2a-3f4d-4a5b-8c6d-7e8f9a0b1c2d",
"attributes": {
"deleted": true
}
}
}

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not delete its owner's account
422Missing or invalid confirmation
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

PATCH /v1/me​

Update the authenticated user's profile (v1)

Updates the authenticated user's own name and/or company from the portal Profile page. Authorized on the first-party interactive session (#1971): a long-lived data key (PAT / opaque tc_ key) is rejected. The body is a JSON:API resource document (data.type = users); both attributes are optional, so a partial update leaves the omitted attribute unchanged, and company may be nulled to clear it. Requires Content-Type: application/vnd.api+json (415 otherwise). There is no user id in the path — the caller can only ever update their own record.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"users"
data.attributesobjectNoNo
data.attributes.namestringNoNo"Jane Doe"
data.attributes.companystringNoYes"Acme Corp"

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/me" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"users","attributes":{"name":"Jane Doe","company":"Acme Corp"}}}'

Example Response​

{
"data": {
"type": "users",
"id": "9b1c1e2a-3f4d-4a5b-8c6d-7e8f9a0b1c2d",
"attributes": {
"name": "Jane Doe",
"email": "[email protected]",
"company": "Acme Corp",
"plan": "pro_monthly",
"subscription_status": "active",
"trial_ends_at": "2026-07-15T00:00:00+00:00"
}
}
}

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not rewrite its owner's profile
415Content-Type is not application/vnd.api+json
422Validation failed
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

PATCH /v1/user/password​

Change the authenticated user's password

Verifies the caller's current password, validates and rehashes the new one, and persists it. On success the user's OTHER OAuth access/refresh tokens are revoked (other login sessions and Passport personal-access tokens stop authenticating; opaque tc_ data keys live in a separate store and are NOT revoked by this sweep) while the current session stays alive. Requires an interactive first-party session; long-lived data keys are rejected.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"user-passwords"
data.attributesobjectNoNo
data.attributes.current_passwordstring (password)YesNo"current-secret"
data.attributes.new_passwordstring (password)YesNo"new-secret-123"
data.attributes.new_password_confirmationstring (password)YesNo"new-secret-123"

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/user/password" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"user-passwords","attributes":{"current_password":"current-secret","new_password":"new-secret-123","new_password_confirmation":"new-secret-123"}}}'

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not change its owner's password
422Wrong current password or new password fails the rules
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/user/password/forgot​

Request a password-reset link

Mints a single-use, expiring opaque reset token for the account holding the supplied address and emails the portal's /reset-password?token=… link to it. Public (no authentication) — a locked-out user has neither a session nor their current password. Always returns 202 whether or not the address matches an account, with a byte-identical body, so the response cannot be used to enumerate registered addresses; a failed email send is swallowed rather than surfaced for the same reason. Throttled per IP (throttle:password-forgot). A second request for the same account replaces the prior pending token rather than adding one.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"user-password-forgots"
data.attributesobjectNoNo
data.attributes.emailstring (email)YesNo"[email protected]"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/user/password/forgot" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"user-password-forgots","attributes":{"email":"[email protected]"}}}'

Error Responses​

StatusDescription
422Validation error (missing or malformed address)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/user/password/reset​

Redeem a password-reset token and set a new password

Redeems the opaque token from the emailed reset link, sets the new password, and consumes the token (single use). Public (no authentication) — the token in the JSON:API body is the sole authorization. On success all of the user's OAuth access/refresh tokens are revoked, so every existing session and Passport personal-access token stops authenticating (unlike the authenticated change-password endpoint, which spares the acting session — a reset has no acting session and may be recovering a compromised account). Opaque tc_ data keys live in a separate store and are NOT revoked by this sweep. An unknown, expired, or already-used token all return the same generic 422 so the response cannot distinguish them. A missing or over-long token never reaches that check — request validation rejects it first with the standard JSON:API 422 carrying a /data/attributes/token source pointer.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"user-password-resets"
data.attributesobjectNoNo
data.attributes.tokenstringYesNo"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f"
data.attributes.passwordstring (password)YesNo"new-secret-123"
data.attributes.password_confirmationstring (password)YesNo"new-secret-123"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/user/password/reset" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"user-password-resets","attributes":{"token":"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f","password":"new-secret-123","password_confirmation":"new-secret-123"}}}'

Error Responses​

StatusDescription
422Unknown, expired, or already-used reset token (single generic error), or a validation error with a source pointer when the token is missing/over-long or the new password fails the rules
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/signup​

Self-service signup (v1)

Creates an unverified user and dispatches a verification email. Public (no authentication). Gated on remaining founding-pool capacity; when the pool is full a waitlist response is returned. The success response is identical whether or not the email already exists (non-enumerating).

Requires a valid invite code (data.attributes.invite_code, issue #2282). A missing code is a 422 validation error; a code that is unknown, revoked, expired, or fully used is rejected with invite_invalid, invite_expired (410) or invite_exhausted. Holding an invite is permission to create an account — it does NOT reserve a founding slot, which is still claimed first-come-first-served at POST /v1/signup/verify. Use POST /v1/invites/validate to check a code without attempting a signup.

A re-submit never changes an existing account's password. When the address already belongs to an account, the submitted password is discarded and the account keeps whatever credential it currently has. For an account that is still unverified the verification email is re-sent, so re-submitting is a valid way to recover a lost link — but the password sent with it does not take effect, and the account's existing password is unaffected. Overwriting it is deliberately not supported: this endpoint is unauthenticated and cannot prove the re-submitter started the signup, so allowing it would let an attacker plant a credential that the victim's own verification click activates. Prefer POST /v1/signup/resend, which recovers an expired link from the token alone and never asks for a password. Because the 202 body is byte-identical on every branch, its meta.message states this conditionally rather than only when it applies.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"signups"
data.attributesobjectNoNo
data.attributes.emailstring (email)YesNo"[email protected]"
data.attributes.passwordstring (password)YesNo"correct horse battery"
data.attributes.invite_codestringYesNo"FOUNDING-2026"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/signup" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"signups","attributes":{"email":"[email protected]","password":"correct horse battery","invite_code":"FOUNDING-2026"}}}'

Error Responses​

StatusDescription
410Invite code has expired
422Validation error, or the invite code is unknown, revoked, or fully used
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/signup/verify​

Verify signup email, start trial, issue API key (v1)

Redeems the emailed verification token: marks the email verified, atomically claims a founding slot, starts a 14-day app-managed trial, issues the single opaque tc_live_ API key (returned once), and sends the welcome email. Public (no authentication) — the token in the JSON:API body is the sole authorization. When the founding pool has filled since signup a waitlist response is returned and no trial is started.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"email-verifications"
data.attributesobjectNoNo
data.attributes.tokenstringYesNo"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/signup/verify" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"email-verifications","attributes":{"token":"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f"}}}'

Error Responses​

StatusDescription
410Verification token has expired
422Verification token is missing, invalid, or already used
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/signup/resend​

Resend the signup verification email from an expired token (v1)

Mints a fresh verification token for the account the supplied token belongs to and re-sends the verification email. Public (no authentication) — the token in the JSON:API body is the sole authorization, which is what lets the marketing site's /verify?token=… page offer a one-click resend when POST /v1/signup/verify has answered 410 token_expired. An expired token is accepted here; that is the whole point of the endpoint.

Token rotation, not extension: a successful resend replaces the stored token and its expiry, so the previous link stops working immediately and the new one carries a full 24-hour window. Because rotation is immediate, a spent token keeps replaying its 202 for 60 seconds — a double-submitted or retried request is idempotent and sends no second email, rather than reporting the link it just replaced as unknown.

The 202 response is identical whether or not the account is already verified (non-enumerating); the email is only dispatched when it is not. A token that resolves to no account — never issued, already rotated, or burned by a completed verification — is answered with 422 token_unknown, which is safe to distinguish because the token is a 64-character random secret rather than a guessable identifier. The token must be sent in the JSON body; a token in the query string is ignored, since a query string is recorded by proxies and travels onward in Referer. Unlike signup and verify, this endpoint is NOT gated on founding-pool capacity: capacity is enforced when the link is redeemed, and a waitlist response here would be indistinguishable from a sent email.

A resend re-asserts the caller's invite claim. Because an expired token is accepted here and rotated into a fresh 24-hour one, an unverified account whose invite hold had already lapsed could otherwise be verified later against a use that had since been given to somebody else, taking an invite past its max_uses. So for an unverified account the hold is re-acquired before the token is rotated, and a resend is refused with 422 invite_exhausted when the invite has been fully claimed in the meantime, or with 422 invite_invalid when the invite has since been revoked (issue #2575). An account that holds no invite claim at all is unaffected, and an already-verified account does no invite work.

Throttled by throttle:signup-resend per IP and per token, on top of the default api limit, because every accepted call sends an email — so a 429 here can arrive well before the general rate limit is spent.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"verification-resends"
data.attributesobjectNoNo
data.attributes.tokenstringYesNo"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/signup/resend" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"verification-resends","attributes":{"token":"kQ8mZ3xR7vL2nP9wB4dF6sT1hJ0yC5gAeU3iO8qW2rY7tK4uM6bN1vX9zD5cH0f"}}}'

Error Responses​

StatusDescription
422Verification token is missing, malformed, or resolves to no account (token_unknown); or the account is unverified and the invite that put it in flight has since been fully claimed (invite_exhausted) or revoked (invite_invalid)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/user/subscription​

Get the authenticated user's subscription/plan and trial state

Returns the authenticated end user's plan, subscription status, trial state, and period/cancellation flags as a JSON:API resource. Read-only; never mutates billing state. A user with no billing account gets a graceful "no plan" resource (200), not a 500.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/user/subscription" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not read its owner's subscription
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/user/usage​

Get the authenticated caller's current rate-limit window

Returns the live rate-limit window (limit, remaining, resets_at) for the authenticated user's tc_live_ API key, as a JSON:API resource. Both credential types work: an opaque tc_live_ API key may read its own usage, and so may an interactive first-party portal session — unlike the sibling account-management endpoints (GET/POST/DELETE /v1/user/api-key, PATCH /v1/user/email), which reject a data key with 403. Whichever credential calls it, the window reported is always the authenticated user's own API-key bucket, deliberately NOT the bucket of the token making this request, since the portal proxies its screens with an interactive session token whose browsing would otherwise be reported as API usage (issue #2304). The call is not metered: this endpoint is exempt from the api rate limiter it reports on, so polling your own usage never consumes the quota being reported (it has its own separate, more permissive limiter, hence the 429 below). A user with no API key is reported as a full, untouched window at their default tier. windows (issue #2559): an additive array reporting every window actually enforced against this user. It always contains an api_key entry (the same numbers as the top-level attributes), plus either a billing_account entry — when the user's OAuth-token traffic is metered against a per-billing-account plan allowance (see PR #2558) — or, when no entitling billing account resolves, a per_token entry whose remaining and resets_at are null (the limiter buckets that case per individual token, which this endpoint cannot sum). Read-only. The portal dashboard derives requests-used as limit - remaining.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/user/usage" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthenticated
403Authenticated as an OAuth client rather than a user, so there is no usage window to report (machine-to-machine client-credentials token)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

PATCH /v1/user/email​

Initiate a change of the authenticated user's login email

Validates a new login-email address (well-formed, unused, and different from the current login), stores it as a pending change, and emails a confirmation link to the NEW address. The login email is NOT changed until the confirmation link is redeemed via POST /v1/user/email/confirm. Authorized on an interactive first-party session (#1971); personal-access / opaque data keys are rejected.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"user-emails"
data.attributesobjectNoNo
data.attributes.emailstring (email)YesNo"[email protected]"

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/user/email" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"user-emails","attributes":{"email":"[email protected]"}}}'

Error Responses​

StatusDescription
401Unauthenticated — no token, an invalid/expired token, or a Passport personal-access token (rejected outright at the auth layer since the opaque-key cutover)
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which authenticates fine on the data endpoints but may not change its owner's login email
422Validation error (invalid, in-use, or unchanged address)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/user/email/confirm​

Confirm a pending login-email change

Redeems the confirmation token emailed to the new address, promotes the pending address to the login email, and marks it verified. The previous address stops authenticating. Followed from an emailed link, so it authenticates on the opaque token alone (no session, no bearer). Rejects a missing, unknown, or expired token.

Authentication: Public — no API token required.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"user-email-confirmations"
data.attributesobjectNoNo
data.attributes.tokenstringYesNo

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/user/email/confirm" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"user-email-confirmations","attributes":{"token":"string"}}}'

Error Responses​

StatusDescription
422Missing, unknown, or expired confirmation token
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

Attributes v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/attributes​

Get all card attributes (v1)

Retrieve a paginated list of all card attributes (autographs, variations, etc.)

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
namestringNoFilter by attribute name. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Auto). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
limitintegerNoNumber of attributes per page
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/attributes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "attributes",
"id": "string",
"attributes": {
"attribute": "Autograph",
"name": "Autograph",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/attributes​

Create a new attribute (v1)

Create a new card attribute (autograph, variation, etc.)

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"attributes"
data.attributesobjectNoNo
data.attributes.attributestringYesNo"AU"
data.attributes.namestringYesNo"Autograph"
data.attributes.descriptionstringNoYes"Player's signature on card"
data.attributes.colorstringNoYes"#FF0000"

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/attributes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"attributes","attributes":{"attribute":"AU","name":"Autograph","description":"Player'\''s signature on card","color":"#FF0000"}}}'

Example Response​

{
"data": {
"type": "attributes",
"id": "string",
"attributes": {
"attribute": "Autograph",
"name": "Autograph",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/attributes/{id}​

Get a specific attribute (v1)

Retrieve detailed information about a specific card attribute by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the attribute to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "attributes",
"id": "string",
"attributes": {
"attribute": "Autograph",
"name": "Autograph",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Attribute not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/attributes/{id}​

Delete an attribute (v1)

Delete an existing card attribute

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the attribute to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Attribute not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/attributes/{id}​

Update an attribute (v1)

Update an existing card attribute

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the attribute to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"attributes"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.attributestringNoNo"AU"
data.attributes.namestringNoNo"Autograph"
data.attributes.descriptionstringNoYes"Player's signature on card"
data.attributes.colorstringNoYes"#FF0000"

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"attributes","id":"string","attributes":{"attribute":"AU","name":"Autograph","description":"Player'\''s signature on card","color":"#FF0000"}}}'

Example Response​

{
"data": {
"type": "attributes",
"id": "string",
"attributes": {
"attribute": "Autograph",
"name": "Autograph",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Attribute not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Billing​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

POST /v1/billing/checkout​

Create a Stripe Checkout Session for self-service subscribe (v1)

Creates a subscription-mode Stripe Checkout Session for the authenticated caller's billing account (lazily creating the account and Stripe customer on first use) and returns the hosted session URL. The plan selects the Stripe price; optional success_url/cancel_url must match the configured trusted-origin allowlist.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
planstringYesNo"starter"The plan slug to subscribe to. Must be one of the plans configured for the API (at launch: starter or pro).
success_urlstring (uri)NoNo"https://app.tradingcardapi.com/account/billing?checkout=success"Optional. Where Stripe returns the user after a completed checkout. Its origin must be in the configured trusted-origin allowlist.
cancel_urlstring (uri)NoNo"https://app.tradingcardapi.com/account/billing?checkout=cancel"Optional. Where Stripe returns the user if they abandon checkout. Its origin must be in the configured trusted-origin allowlist.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/billing/checkout" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"plan":"starter","success_url":"https://app.tradingcardapi.com/account/billing?checkout=success","cancel_url":"https://app.tradingcardapi.com/account/billing?checkout=cancel"}'

Example Response​

{
"url": "https://checkout.stripe.com/c/pay/cs_test_abc123"
}

Error Responses​

StatusDescription
401Unauthenticated
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which may not subscribe its owner
409Caller's billing account already holds an entitling subscription
422Unknown plan, or success_url/cancel_url origin not in the trusted allowlist
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
502Stripe checkout session creation failed

POST /v1/billing/portal​

Create a Stripe Customer Portal session (v1)

Creates a Stripe Billing Portal session for the authenticated caller's billing account (lazily creating the account and Stripe customer on first use) and returns the hosted session URL. An optional return_url must match the configured trusted-origin allowlist.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
return_urlstring (uri)NoNo"https://app.tradingcardapi.com/account/billing"Optional. Where Stripe returns the user after the portal session. Its origin must be in the configured trusted-origin allowlist.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/billing/portal" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"return_url":"https://app.tradingcardapi.com/account/billing"}'

Example Response​

{
"url": "https://billing.stripe.com/session/test_abc123"
}

Error Responses​

StatusDescription
401Unauthenticated
403Authenticated but not an interactive first-party session — e.g. an opaque tc_ data key, which may not open its owner's billing portal
422return_url origin not in the trusted allowlist
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
502Stripe portal session creation failed

GET /v1/founding-slots/remaining​

Get the remaining founding-customer slots

Returns the number of founding-customer slots still available as a single derived count (capacity minus the billing accounts currently trialing or active). Public and unauthenticated — it exposes only the aggregate remaining count for the marketing-site indicator, no per-user state. Throttled by the default anonymous rate limit.

Authentication: Public — no API token required.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/founding-slots/remaining" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

Brands v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/brands​

Get all brands (v1)

Retrieve a list of all trading card brands

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
includestringNoComma-separated list of relationships to include. Supported: sets

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/brands" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "brands",
"id": "string",
"attributes": {
"name": "Topps",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/brands​

Create a new brand (v1)

Create a new trading card brand

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"brands"
data.attributesobjectNoNo
data.attributes.namestringYesNo"Topps"
data.attributes.descriptionstringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/brands" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"brands","attributes":{"name":"Topps","description":"string"}}}'

Example Response​

{
"data": {
"type": "brands",
"id": "string",
"attributes": {
"name": "Topps",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/brands/{id}​

Get a specific brand (v1)

Retrieve detailed information about a specific brand by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the brand to retrieve
includestringNoComma-separated list of relationships to include. Supported: sets

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/brands/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "brands",
"id": "string",
"attributes": {
"name": "Topps",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Brand not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/brands/{id}​

Delete a brand (v1)

Delete an existing brand

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the brand to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/brands/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Brand not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/brands/{id}​

Update a brand (v1)

Update an existing brand

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the brand to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"brands"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.namestringNoNo"Topps"
data.attributes.descriptionstringNoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/brands/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"brands","id":"string","attributes":{"name":"Topps","description":"string"}}}'

Example Response​

{
"data": {
"type": "brands",
"id": "string",
"attributes": {
"name": "Topps",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Brand not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Cards v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/cards​

Get all cards (v1)

Retrieve a paginated list of all trading cards in the system

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[name]stringNoFilter by card name. This is the card's generated display name -- the card number, the players or teams on it, the card title, any attributes (RC, AU, ...) and the serial, joined in that order -- so an exact match has to reproduce that whole composed string. Exact match only. Unlike the other string filters in this API, the like: operator is NOT accepted here and returns a 400: it compiles to a leading-wildcard LIKE '%...%', which no index can serve, and api_cards is by far the largest table in the API. Substring search on card names is tracked at issue #2590. A card whose name literally begins like: therefore cannot be matched on its full name.
filter[set_id]stringNoFilter cards by set UUID
filter[player_id]stringNoFilter cards by player UUID. Returns every card the player appears on, both directly and via a player-team.
filter[team_id]stringNoFilter cards by team UUID. Returns every card the team appears on, both directly and via one of its player-teams.
includestringNoComma-separated list of relationships to include (set,oncard,attributes,children)
pageintegerNoPage number for pagination
per_pageintegerNoNumber of items per page (max 100, default 25)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/cards" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
400Bad Request — the query string contains a parameter this endpoint does not accept, or the requested page size exceeds the maximum of 100. Details
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/cards​

Create a new card (v1)

Create a new trading card record. A client-generated data.id (JSON:API §7.2.1) may be supplied to pin the new card's UUID, which makes a re-create of the same logical card detectable rather than duplicating it; omit it and the server generates a v4 UUID. Creating over an id that is already taken returns 409 — this endpoint is create-only. For upsert-by-id semantics use POST /internal/card-batches.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"cards"
data.idstring (uuid)NoNo"550e8400-e29b-41d4-a716-446655440000"Optional client-generated UUID for the new card. Omit to let the server generate one. Optional but non-null when present — validation is sometimes|uuid, so an explicit null is rejected.
data.attributesobjectNoNo
data.attributes.numberstringNoNo"23"Card number within the set
data.attributes.serial_numberstringNoYes"001/100"
data.attributes.image_uuidstring (uuid)NoYes"550e8400-e29b-41d4-a716-446655440000"UUID reference for card image
data.attributes.titlestringNoYes"Rookie Card"
data.attributes.notesstringNoYes
data.relationshipsobjectNoNo
data.relationships.setobjectNoNo
data.relationships.set.dataobjectNoNo
data.relationships.set.data.typestringNoNo"sets"
data.relationships.set.data.idstring (uuid)NoNo
data.relationships.oncardobjectNoNo
data.relationships.oncard.dataarray of objectNoNo
data.relationships.oncard.data[].typestringNoNo
data.relationships.oncard.data[].idstring (uuid)NoNo

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/cards" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"cards","id":"550e8400-e29b-41d4-a716-446655440000","attributes":{"number":"23","serial_number":"001/100","image_uuid":"550e8400-e29b-41d4-a716-446655440000","title":"Rookie Card","notes":"string"},"relationships":{"set":{"data":{"type":"sets","id":"string"}},"oncard":{"data":[{"type":"string","id":"string"}]}}}}'

Example Response​

{
"data": {
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
409A card already exists at the supplied client-generated data.id
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/cards/{id}​

Get a specific card (v1)

Retrieve detailed information about a specific trading card by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the card to retrieve
includestringNoComma-separated list of relationships to include (set,oncard,attributes,children)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/cards/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/cards/{id}​

Delete a card (v1)

Delete an existing trading card record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the card to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/cards/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/cards/{id}​

Update a card (v1)

Update an existing trading card record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the card to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"cards"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.numberstringNoNo"23"
data.attributes.serial_numberstringNoYes"001/100"
data.attributes.image_uuidstring (uuid)NoYes"550e8400-e29b-41d4-a716-446655440000"UUID reference for card image
data.attributes.titlestringNoYes"Rookie Card"
data.attributes.notesstringNoYes
data.attributes.attributesarray of objectNoNoExtra attributes for the card
data.attributes.attributes[].idstring (uuid)NoNo
data.attributes.attributes[].valuestringNoNo
data.attributes.field_overridesarray of stringNoYesFields not inherited from parent (parallel cards only)
data.relationshipsobjectNoNo
data.relationships.setobjectNoNo
data.relationships.set.dataobjectNoNo
data.relationships.set.data.typestringNoNo"sets"
data.relationships.set.data.idstring (uuid)NoNo
data.relationships.oncardobjectNoNo
data.relationships.oncard.dataarray of objectNoNo
data.relationships.oncard.data[].typestringNoNo
data.relationships.oncard.data[].idstring (uuid)NoNo

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/cards/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"cards","id":"string","attributes":{"number":"23","serial_number":"001/100","image_uuid":"550e8400-e29b-41d4-a716-446655440000","title":"Rookie Card","notes":"string","attributes":[{"id":"string","value":"string"}],"field_overrides":["string"]},"relationships":{"set":{"data":{"type":"sets","id":"string"}},"oncard":{"data":[{"type":"string","id":"string"}]}}}}'

Example Response​

{
"data": {
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Card Images​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/card-images​

List all card images

List all card images

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
includestringNoInclude related resources (card)
pageintegerNoPage number for pagination
per_pageintegerNoNumber of items per page (default 50, max 100)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/card-images" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/card-images​

Upload a new card image

Upload a new card image

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: multipart/form-data

FieldTypeRequiredNullableExampleDescription
filestring (binary)YesNoImage file (JPEG, PNG, or WebP, max 10MB, max 4000x4000px)
datastring (json)YesNo"{\"type\":\"card_images\",\"attributes\":{\"card_id\":\"uuid\",\"image_type\":\"front\"}}"JSON:API formatted data

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/card-images" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json" \
-F 'file=@/path/to/file' \
-F 'data={"type":"card_images","attributes":{"card_id":"uuid","image_type":"front"}}'

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/card-images/{id}​

Get a specific card image

Get a specific card image

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesCard image UUID
includestringNoInclude related resources (card)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/card-images/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card image not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

DELETE /v1/card-images/{id}​

Delete a card image

Delete a card image

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesCard image UUID

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/card-images/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card image not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

PATCH /v1/card-images/{id}​

Update a card image

Update a card image

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesCard image UUID

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/card-images/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card image not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/card-images/{card_image}/download​

Download the actual image file

Download/stream the actual image file

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
card_imagestringYesCard image UUID
sizestringNoImage size variant. Sizes configured in config/images.php (default: small/medium/large)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/card-images/{card_image}/download" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: image/*"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Card image or variant not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/card-image-batches​

Upload multiple card images in a batch

Accepts up to 50 images per request. Returns immediately with a batch ID for polling status. The legacy POST /v1/card-images/bulk URL is a deprecated alias for this endpoint (slated for removal in v2).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: multipart/form-data

FieldTypeRequiredNullableExampleDescription
files[]array of stringNoNoImage files (max 50, each max 10MB, JPEG/PNG/WebP)
datastring (json)YesNo"{\"type\":\"bulk_card_images\",\"attributes\":{\"mappings\":[...]}}"JSON:API formatted data with mappings

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/card-image-batches" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json" \
-F 'files[]=@/path/to/file' \
-F 'data={"type":"bulk_card_images","attributes":{"mappings":[...]}}'

Error Responses​

StatusDescription
401The caller identity could not be resolved, so the batch would have no owner and would be unreadable by anyone.
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

GET /v1/card-image-batches/{card_image_batch}​

Get bulk upload batch status

Returns bulk upload batch status and progress. Poll to track progress. The legacy GET /v1/card-images/bulk/{batch_id} URL is a deprecated alias for this endpoint (slated for removal in v2).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
card_image_batchstringYesBatch UUID

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/card-image-batches/{card_image_batch}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Batch not found. Batches are scoped to the caller that created them, so a batch belonging to another caller is indistinguishable from one that does not exist.
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

Genres v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/genres​

Get all genres (v1)

Retrieve a paginated list of all trading card genres

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
limitintegerNoNumber of genres per page
filter[name]stringNoFilter by genre name. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Base). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
namestringNoDeprecated alias for filter[name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
includestringNoComma-separated list of relationships to include
filter[status]stringNoFilter genres by soft-delete state. Use 'deleted' to list only soft-deleted genres or 'active' for live genres (the default).

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/genres" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "genres",
"id": "string",
"attributes": {
"name": "Baseball",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
]
}

Error Responses​

StatusDescription
400Invalid filter parameter, or an unrecognized query parameter
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/genres​

Create a new genre (v1)

Create a new trading card genre, restoring if previously soft-deleted

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"genres"
data.attributesobjectNoNo
data.attributes.namestringYesNo"Baseball"
data.attributes.descriptionstringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/genres" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"genres","attributes":{"name":"Baseball","description":"string"}}}'

Example Response​

{
"data": {
"type": "genres",
"id": "string",
"attributes": {
"name": "Baseball",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/genres/{id}​

Get a specific genre (v1)

Retrieve detailed information about a specific genre by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the genre to retrieve
includestringNoComma-separated list of relationships to include
include_trashedbooleanNoWhen true, a soft-deleted genre is returnable by id. Defaults to false (soft-deleted genres 404).

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/genres/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "genres",
"id": "string",
"attributes": {
"name": "Baseball",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Genre not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/genres/{id}​

Delete a genre (v1)

Soft delete an existing genre record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the genre to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/genres/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Genre not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/genres/{id}​

Update a genre (v1)

Update an existing genre record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the genre to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"genres"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.namestringNoNo"Baseball"
data.attributes.descriptionstringNoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/genres/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"genres","id":"string","attributes":{"name":"Baseball","description":"string"}}}'

Example Response​

{
"data": {
"type": "genres",
"id": "string",
"attributes": {
"name": "Baseball",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Genre not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Manufacturers v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/manufacturers​

Get all manufacturers (v1)

Retrieve a list of all trading card manufacturers

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/manufacturers" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "manufacturers",
"id": "string",
"attributes": {
"name": "Topps Company",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/manufacturers​

Create a new manufacturer (v1)

Create a new trading card manufacturer

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"manufacturers"
data.attributesobjectNoNo
data.attributes.namestringYesNo"Topps Company"
data.attributes.descriptionstringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/manufacturers" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"manufacturers","attributes":{"name":"Topps Company","description":"string"}}}'

Example Response​

{
"data": {
"type": "manufacturers",
"id": "string",
"attributes": {
"name": "Topps Company",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/manufacturers/{id}​

Get a specific manufacturer (v1)

Retrieve detailed information about a specific manufacturer by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the manufacturer to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/manufacturers/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "manufacturers",
"id": "string",
"attributes": {
"name": "Topps Company",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Manufacturer not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/manufacturers/{id}​

Delete a manufacturer (v1)

Delete an existing manufacturer

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the manufacturer to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/manufacturers/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Manufacturer not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/manufacturers/{id}​

Update a manufacturer (v1)

Update an existing manufacturer

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the manufacturer to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"manufacturers"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.namestringNoNo"Topps Company"
data.attributes.descriptionstringNoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/manufacturers/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"manufacturers","id":"string","attributes":{"name":"Topps Company","description":"string"}}}'

Example Response​

{
"data": {
"type": "manufacturers",
"id": "string",
"attributes": {
"name": "Topps Company",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Manufacturer not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

ObjectAttributes v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/object-attributes​

Get all object attributes (v1)

Retrieve a paginated list of all object attributes (card-specific attribute instances)

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
limitintegerNoNumber of object attributes per page
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/object-attributes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "object-attributes",
"id": "string",
"attributes": {
"attribute_id": "string",
"attribute_value": "Authenticated",
"object_type": "App\\Models\\Card",
"object_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/object-attributes​

Create a new object attribute (v1)

Create a new object attribute instance linking an attribute to a specific object (card)

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"object-attributes"
data.attributesobjectNoNo
data.attributes.attribute_idstring (uuid)YesNoID of the attribute definition
data.attributes.attribute_valuestringYesNo"Authenticated"Value of the attribute for this object
data.attributes.object_typestringYesNo"App\\Models\\Card"Type of object this attribute is attached to
data.attributes.object_idstring (uuid)YesNoID of the object this attribute is attached to

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/object-attributes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"object-attributes","attributes":{"attribute_id":"string","attribute_value":"Authenticated","object_type":"App\\Models\\Card","object_id":"string"}}}'

Example Response​

{
"data": {
"type": "object-attributes",
"id": "string",
"attributes": {
"attribute_id": "string",
"attribute_value": "Authenticated",
"object_type": "App\\Models\\Card",
"object_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/object-attributes/{id}​

Get a specific object attribute (v1)

Retrieve detailed information about a specific object attribute by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the object attribute to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/object-attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "object-attributes",
"id": "string",
"attributes": {
"attribute_id": "string",
"attribute_value": "Authenticated",
"object_type": "App\\Models\\Card",
"object_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Object attribute not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/object-attributes/{id}​

Delete an object attribute (v1)

Delete an existing object attribute instance

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the object attribute to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/object-attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Object attribute not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/object-attributes/{id}​

Update an object attribute (v1)

Update an existing object attribute instance

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the object attribute to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"object-attributes"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.attribute_idstring (uuid)NoNo
data.attributes.attribute_valuestringNoNo"Authenticated"
data.attributes.object_typestringNoNo"App\\Models\\Card"
data.attributes.object_idstring (uuid)NoNo

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/object-attributes/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"object-attributes","id":"string","attributes":{"attribute_id":"string","attribute_value":"Authenticated","object_type":"App\\Models\\Card","object_id":"string"}}}'

Example Response​

{
"data": {
"type": "object-attributes",
"id": "string",
"attributes": {
"attribute_id": "string",
"attribute_value": "Authenticated",
"object_type": "App\\Models\\Card",
"object_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Object attribute not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Players v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/players​

Get all players (v1)

Retrieve a paginated list of all players with optional filtering

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[first_name]stringNoFilter by player first name. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Mich). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[last_name]stringNoFilter by player last name. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Jord). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[full_name]stringNoFilter by full name (searches both first and last name). The value is an exact match by default. Prefix the whole value with like: for a case-insensitive substring match on each name token (for example like:Mich Jord). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
first_namestringNoDeprecated alias for filter[first_name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
last_namestringNoDeprecated alias for filter[last_name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
full_namestringNoDeprecated alias for filter[full_name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
limitintegerNoNumber of players per page (max 100, default 25)
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/players" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "players",
"id": "string",
"attributes": {
"name": "Michael Jordan",
"first_name": "Michael",
"last_name": "Jordan",
"position": "Shooting Guard",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
400Bad Request — the query string contains a parameter this endpoint does not accept, or the requested page size exceeds the maximum of 100. Details
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/players​

Create a new player (v1)

Create a new player record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"players"
data.attributesobjectNoNo
data.attributes.first_namestringNoNo"Michael"
data.attributes.last_namestringNoNo"Jordan"
data.attributes.positionstringNoYes"Shooting Guard"
data.attributes.full_namestringNoNo"Michael Jordan"Alternative to first_name/last_name

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/players" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"players","attributes":{"first_name":"Michael","last_name":"Jordan","position":"Shooting Guard","full_name":"Michael Jordan"}}}'

Example Response​

{
"data": {
"type": "players",
"id": "string",
"attributes": {
"name": "Michael Jordan",
"first_name": "Michael",
"last_name": "Jordan",
"position": "Shooting Guard",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/players/{id}​

Get a specific player (v1)

Retrieve detailed information about a specific player by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/players/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "players",
"id": "string",
"attributes": {
"name": "Michael Jordan",
"first_name": "Michael",
"last_name": "Jordan",
"position": "Shooting Guard",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/players/{id}​

Delete a player (v1)

Delete an existing player record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/players/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/players/{id}​

Update a player (v1)

Update an existing player record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"players"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.first_namestringNoNo"Michael"
data.attributes.last_namestringNoNo"Jordan"
data.attributes.positionstringNoYes"Shooting Guard"

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/players/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"players","id":"string","attributes":{"first_name":"Michael","last_name":"Jordan","position":"Shooting Guard"}}}'

Example Response​

{
"data": {
"type": "players",
"id": "string",
"attributes": {
"name": "Michael Jordan",
"first_name": "Michael",
"last_name": "Jordan",
"position": "Shooting Guard",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PlayerTeams v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/player-teams​

Get all player-team associations (v1)

Retrieve a paginated list of player-team associations with optional filtering. This resource is deliberately filterable by foreign key only: it owns no human-readable string column of its own, so there is nothing for a name filter to match and no like: filter is offered. To search by name, filter /v1/players or /v1/teams and follow the relationship. See ADR-007 (the v1 filter-set convention).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[team_id]stringNoFilter by team UUID. Exact match only -- like: is not accepted on a foreign key (ADR-007).
filter[player_id]stringNoFilter by player UUID. Exact match only -- like: is not accepted on a foreign key (ADR-007).
team_idstringNoDeprecated alias for filter[team_id]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
player_idstringNoDeprecated alias for filter[player_id]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
limitintegerNoNumber of player-teams per page
includestringNoComma-separated list of relationships to include (player,team)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/player-teams" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "playerteams",
"id": "string",
"attributes": {
"name": "Michael Jordan - Chicago Bulls",
"player_id": "string",
"team_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
400Bad Request — the query string contains a parameter this endpoint does not accept, or the requested page size exceeds the maximum of 100. Details
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/player-teams​

Create a new player-team association (v1)

Create a new player-team association record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"playerteams"
data.attributesobjectNoNo
data.attributes.player_idstring (uuid)YesNoID of the player
data.attributes.team_idstring (uuid)YesNoID of the team

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/player-teams" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"playerteams","attributes":{"player_id":"string","team_id":"string"}}}'

Example Response​

{
"data": {
"type": "playerteams",
"id": "string",
"attributes": {
"name": "Michael Jordan - Chicago Bulls",
"player_id": "string",
"team_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/player-teams/{id}​

Get a specific player-team association (v1)

Retrieve detailed information about a specific player-team association by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player-team association to retrieve
includestringNoComma-separated list of relationships to include (player,team)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/player-teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "playerteams",
"id": "string",
"attributes": {
"name": "Michael Jordan - Chicago Bulls",
"player_id": "string",
"team_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player-team association not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/player-teams/{id}​

Delete a player-team association (v1)

Delete an existing player-team association record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player-team association to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/player-teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player-team association not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/player-teams/{id}​

Update a player-team association (v1)

Update an existing player-team association record (PATCH only; PUT is not supported and returns 405 Method Not Allowed).

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the player-team association to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"playerteams"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.player_idstring (uuid)NoNoID of the player
data.attributes.team_idstring (uuid)NoNoID of the team

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/player-teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"playerteams","id":"string","attributes":{"player_id":"string","team_id":"string"}}}'

Example Response​

{
"data": {
"type": "playerteams",
"id": "string",
"attributes": {
"name": "Michael Jordan - Chicago Bulls",
"player_id": "string",
"team_id": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Player-team association not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Sets v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/sets​

Get all card sets (v1)

Retrieve a paginated list of all trading card sets

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
includestringNoComma-separated list of relationships to include
per_pageintegerNoNumber of sets per page (max 100, default 25)
limitintegerNoNumber of sets per page (deprecated, use per_page instead)
order_bystringNoField to order by
sortstringNoSort direction
filter[name]stringNoFilter by set name. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:2021 Topps). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[genre]stringNoFilter by genre ID
filter[year]stringNoFilter by year ID
filter[brand]stringNoFilter by brand ID
filter[manufacturer]stringNoFilter by manufacturer ID
filter[parent_id]stringNoFilter by parent set ID (returns child sets/parallels of the specified parent)
namestringNoDeprecated alias for filter[name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
genrestringNoDeprecated alias for filter[genre]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
yearstringNoDeprecated alias for filter[year]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
brandstringNoDeprecated alias for filter[brand]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
manufacturerstringNoDeprecated alias for filter[manufacturer]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
parent_idstringNoDeprecated alias for filter[parent_id]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
scopestringNoRow scope for the listing. root (the default) returns only sets without a parent, so parallels, inserts, autograph subsets and variations are omitted -- the default meta.pagination.total is therefore a count of root sets, not of the whole catalog. all returns every set. Ignored when parent_id is supplied, which always returns that parent's children. When scope is omitted a name query searches every set for backward compatibility; pass scope=root explicitly to keep a name search to root sets.
filter[status]stringNoFilter by status (requires X-TCAPI-Ignore-Status header to see draft sets)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/sets" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"pagination": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
},
"scope": {
"applied": "root_sets_only",
"description": "Only sets without a parent are listed, so parallels, inserts, autograph subsets and variations are omitted. This is a default scope, not a limit on your account. Add ?scope=all to list every set, or ?parent_id={id} to list one set's children."
}
}
}

Error Responses​

StatusDescription
400Bad Request — the query string contains a parameter this endpoint does not accept, or the requested page size exceeds the maximum of 100. Details
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/sets​

Create a new set (v1)

Create a new trading card set

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"sets"
data.attributesobjectNoNo
data.attributes.namestringYesNo"1989 Topps Baseball"
data.attributes.descriptionstringNoYes
data.attributes.total_cardsintegerNoYes792
data.attributes.genre_idstring (uuid)NoYes
data.attributes.manufacturer_idstring (uuid)NoYes
data.attributes.brand_idstring (uuid)NoYes
data.attributes.year_idstring (uuid)NoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/sets" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"sets","attributes":{"name":"1989 Topps Baseball","description":"string","total_cards":792,"genre_id":"string","manufacturer_id":"string","brand_id":"string","year_id":"string"}}}'

Example Response​

{
"data": {
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/sets/{id}​

Get a specific set (v1)

Retrieve detailed information about a specific trading card set by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/sets/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/sets/{id}​

Delete a set (v1)

Delete an existing trading card set. By default the deletion is refused with a 409 when the set is still published or still has child records (cards, set sources, subsets); the response names the specific blocker(s). Pass force=true to cascade-delete those children and remove the set in a single call.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set to delete
forcebooleanNoWhen true, cascade-delete remaining children (cards, set sources, subsets) and remove the set even if it is published. When false or omitted, a published set or a set with remaining children is refused with a structured 409.
confirmbooleanNoReserved confirmation flag accepted for forward compatibility with the documented delete contract; parsed as a boolean and currently advisory.

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/sets/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
409Set deletion blocked — published or has remaining children and force was not set
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/sets/{id}​

Update a set (v1)

Update an existing trading card set

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"sets"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.namestringNoNo"1989 Topps Baseball"
data.attributes.descriptionstringNoYes
data.attributes.total_cardsintegerNoYes792
data.attributes.genre_idstring (uuid)NoYes
data.attributes.manufacturer_idstring (uuid)NoYes
data.attributes.brand_idstring (uuid)NoYes
data.attributes.year_idstring (uuid)NoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/sets/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"sets","id":"string","attributes":{"name":"1989 Topps Baseball","description":"string","total_cards":792,"genre_id":"string","manufacturer_id":"string","brand_id":"string","year_id":"string"}}}'

Example Response​

{
"data": {
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/sets/{set}/checklist​

Get set checklist (v1)

Retrieve the complete checklist for a trading card set including all cards. Supports compact format for large sets to avoid response size limits. Compact format returns only id, number, name, has_player, and has_team fields, reducing response size by ~75%.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the set to get checklist for
formatstringNoResponse format: 'full' returns all card fields, 'compact' returns only id, number, name, has_player, and has_team
pageintegerNoPage number for pagination (starts at 1)
per_pageintegerNoNumber of cards per page (max 100, returns all if not specified)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/sets/{set}/checklist" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
},
"included": [
{
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/sets/{set}/checklist​

Add checklist to set (v1)

Add or import a checklist to a trading card set. Can either generate empty cards or parse a detailed checklist.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the set to add checklist to
queuebooleanNoQueue the import for async processing. When omitted, large checklists (more than 50 lines) are auto-queued and smaller ones run synchronously. Pass queue=true to force async or queue=false to force sync.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"checklist"
data.attributesobjectNoNo
data.attributes.linesarray of stringNoNo["# Base Set","1 Mike Trout - Los Angeles Angels"]Checklist lines to parse, one entry per line. Lines starting with '#' denote a section. More than 50 lines are auto-queued when the queue parameter is omitted.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/sets/{set}/checklist" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"checklist","attributes":{"lines":["# Base Set","1 Mike Trout - Los Angeles Angels"]}}}'

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/sets/{set}/checklist​

Delete set checklist (v1)

Bulk delete cards from a trading card set. Supports optional range filtering by card number. Without range parameters, all cards in the set are deleted.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the set to delete cards from
from_numberintegerNoStart of card number range to delete (inclusive, integer >= 1)
to_numberintegerNoEnd of card number range to delete (inclusive, integer >= 1, must be >= from_number)
queuebooleanNoQueue the deletion for async processing (recommended for large sets)

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/sets/{set}/checklist" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "bulk_delete_result",
"attributes": {
"cards_deleted": 50,
"set_id": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
403Forbidden - missing delete scope
404Set not found
422Validation error - invalid from_number or to_number
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.

POST /v1/sets/{id}/actions/sync-parallel​

Sync parallel set with parent (v1)

Add missing cards from parent set to a parallel set. This endpoint finds cards in the parent set that don't exist in the parallel set and creates them with their on-card relationships and attributes. This is the canonical JSON:API action-namespace route; the legacy POST /v1/sets/{id}/sync-parallel path is a deprecated alias.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the parallel set to sync
queuestringNoQueue the sync for async processing. Defaults to "auto", which forces queued processing when the parent set has more than 20 cards and otherwise runs the sync inline. Pass "true" to always queue or "false" to always run inline.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"sync_parallel"
data.attributesobjectNoNoNo attributes currently required. Reserved for future options.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/sets/{id}/actions/sync-parallel" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"sync_parallel","attributes":{}}}'

Example Response​

{
"data": {
"type": "sync_result",
"id": "string",
"attributes": {
"cards_created": 15,
"cards_updated": 0,
"cards_skipped": 85
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
422Invalid operation (set is not a parallel set or has no parent)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/sets/{id}/sync-parallel​

Sync parallel set with parent (v1) — DEPRECATED alias

Deprecated RPC-style alias of POST /v1/sets/{id}/actions/sync-parallel. Behaves identically but responds with deprecation headers (Deprecation, Sunset, Link, Warning). Retained for a removal window; migrate to the action-namespace route. (issue #1500)

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the parallel set to sync
queuestringNoQueue the sync for async processing. Defaults to "auto", which forces queued processing when the parent set has more than 20 cards and otherwise runs the sync inline. Pass "true" to always queue or "false" to always run inline.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"sync_parallel"
data.attributesobjectNoNoNo attributes currently required. Reserved for future options.

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/sets/{id}/sync-parallel" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"sync_parallel","attributes":{}}}'

Example Response​

{
"data": {
"type": "sync_result",
"id": "string",
"attributes": {
"cards_created": 15,
"cards_updated": 0,
"cards_skipped": 85
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
422Invalid operation (set is not a parallel set or has no parent)
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Set Sources v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/set-sources​

Get all set sources (v1)

Retrieve all set sources. Filter by set_id and/or source_type using filter[] params.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[set_id]stringNoFilter by set UUID
filter[source_type]stringNoFilter by source type
includestringNoComma-separated list of relationships to include (set)
pageintegerNoPage number for pagination
per_pageintegerNoNumber of items per page (default 50, max 200)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/set-sources" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "set_sources",
"id": "string",
"attributes": {
"source_url": "https://example.com/checklist",
"source_name": "CardboardConnection",
"source_type": "checklist",
"verified_at": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/set-sources​

Create a new set source (v1)

Create a new set source tracking record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"set_sources"
data.attributesobjectNoNo
data.attributes.set_idstring (uuid)YesNo"550e8400-e29b-41d4-a716-446655440000"
data.attributes.source_urlstring (url)YesNo"https://example.com/checklist"
data.attributes.source_namestringNoYes"CardboardConnection"
data.attributes.source_typestringYesNo"checklist"
data.attributes.verified_atstring (date-time)NoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/set-sources" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"set_sources","attributes":{"set_id":"550e8400-e29b-41d4-a716-446655440000","source_url":"https://example.com/checklist","source_name":"CardboardConnection","source_type":"checklist","verified_at":"string"}}}'

Example Response​

{
"data": {
"type": "set_sources",
"id": "string",
"attributes": {
"source_url": "https://example.com/checklist",
"source_name": "CardboardConnection",
"source_type": "checklist",
"verified_at": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/set-sources/{id}​

Get a specific set source (v1)

Retrieve detailed information about a specific set source by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set source to retrieve
includestringNoComma-separated list of relationships to include (set)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/set-sources/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "set_sources",
"id": "string",
"attributes": {
"source_url": "https://example.com/checklist",
"source_name": "CardboardConnection",
"source_type": "checklist",
"verified_at": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set source not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/set-sources/{id}​

Delete a set source (v1)

Delete an existing set source

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set source to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/set-sources/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set source not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/set-sources/{id}​

Update a set source (v1)

Update an existing set source

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the set source to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"set_sources"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.source_urlstring (url)NoNo
data.attributes.source_namestringNoYes
data.attributes.source_typestringNoNo
data.attributes.verified_atstring (date-time)NoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/set-sources/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"set_sources","id":"string","attributes":{"source_url":"string","source_name":"string","source_type":"string","verified_at":"string"}}}'

Example Response​

{
"data": {
"type": "set_sources",
"id": "string",
"attributes": {
"source_url": "https://example.com/checklist",
"source_name": "CardboardConnection",
"source_type": "checklist",
"verified_at": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set source not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Statistics v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/stats/{type}​

Get statistics for a model type (v1)

Retrieve daily statistics showing creation and deletion counts for a specific model type. For the set-derived types (cards, sets) the series is filtered to the set statuses the caller's token may see; taxonomy types are ungated.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
typestringYesType of model to get statistics for (e.g., cards, sets, players)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/stats/{type}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "stats",
"attributes": {
"model": "cards",
"unit": "daily",
"count": 30,
"stats": [
{
"date": "2024-01-15",
"count": 5,
"total": 150
}
]
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Model type not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/stats/counts​

Get current counts for all entity types

Get entity counts by status. Cached for 1 hour. Public and unauthenticated. Unauthenticated callers, and tokens without the internal, read:all-status or read:draft scope, see a published-only view: total equals published and draft is 0.

Authentication: Public — no API token required.

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/stats/counts" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "stats",
"attributes": {
"counts": [
{
"entity_type": "set",
"total": 730,
"published": 730,
"draft": 0,
"archived": 0
}
]
}
}
}

Error Responses​

StatusDescription
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/stats/snapshots​

Get historical snapshots with optional filtering

Get historical snapshots with date/type filters. Public and unauthenticated. Unauthenticated callers, and tokens without the internal, read:all-status or read:draft scope, see a published-only view: total equals published and draft is 0.

Authentication: Public — no API token required.

Parameters​

NameTypeRequiredDescription
entity_typestringNoFilter by entity type
fromstringNoFilter snapshots from this date (YYYY-MM-DD)
tostringNoFilter snapshots to this date (YYYY-MM-DD)
per_pageintegerNoNumber of results per page (default: 100, max: 500)
pageintegerNoPage number

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/stats/snapshots" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "snapshots",
"attributes": {
"snapshots": [
{
"date": "2024-01-15",
"entity_type": "set",
"total": 730,
"published": 730,
"draft": 0,
"archived": 0
}
],
"entity_type": "set",
"from": "string",
"to": "string"
}
},
"meta": {
"total": 100,
"per_page": 100,
"current_page": 1,
"last_page": 1
}
}

Error Responses​

StatusDescription
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/stats/growth​

Get growth metrics for a specific time period

Compare current counts to previous period. Cached for 1 hour. Public and unauthenticated. Unauthenticated callers, and tokens without the internal, read:all-status or read:draft scope, get metrics derived from published counts rather than totals.

Authentication: Public — no API token required.

Parameters​

NameTypeRequiredDescription
periodstringNoTime period for comparison

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/stats/growth" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "growth",
"attributes": {
"period": "7d",
"metrics": [
{
"entity_type": "set",
"current": 730,
"previous": 714,
"change": 16,
"percentage_change": 2.24
}
]
}
}
}

Error Responses​

StatusDescription
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Teams v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/teams​

Get all teams (v1)

Retrieve a paginated list of all teams with optional filtering

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
filter[name]stringNoFilter by full team name (searches both location and mascot). The value is an exact match by default. Prefix the whole value with like: for a case-insensitive substring match on each name token (for example like:Chic Bull). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[location]stringNoFilter by team location. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Chic). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[mascot]stringNoFilter by team mascot. The value is an exact match by default. Prefix it with like: for a case-insensitive substring match (for example like:Bull). Inside a like: value, % and _ are matched literally rather than acting as SQL wildcards.
filter[genre_id]stringNoFilter by genre UUID. Exact match only -- like: is not accepted on a foreign key (ADR-007).
locationstringNoDeprecated alias for filter[location]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
mascotstringNoDeprecated alias for filter[mascot]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
namestringNoDeprecated alias for filter[name]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
genre_idstringNoDeprecated alias for filter[genre_id]. Still accepted, but a request that uses it receives Deprecation and Sunset response headers; migrate to the bracketed spelling.
limitintegerNoNumber of teams per page (max 100, default 25)
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/teams" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "teams",
"id": "string",
"attributes": {
"name": "Chicago Bulls",
"city": "Chicago",
"abbreviation": "CHI",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
],
"included": [
{}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
400Invalid pagination parameter (limit exceeds the maximum of 100), or an unrecognized query parameter
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/teams​

Create a new team (v1)

Create a new team record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"teams"
data.attributesobjectNoNo
data.attributes.locationstringNoNo"Chicago"
data.attributes.mascotstringNoNo"Bulls"
data.attributes.citystringNoYes"Chicago"
data.attributes.abbreviationstringNoYes"CHI"
data.attributes.namestringNoNo"Chicago Bulls"Alternative to location/mascot
data.attributes.genre_idstring (uuid)NoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/teams" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"teams","attributes":{"location":"Chicago","mascot":"Bulls","city":"Chicago","abbreviation":"CHI","name":"Chicago Bulls","genre_id":"string"}}}'

Example Response​

{
"data": {
"type": "teams",
"id": "string",
"attributes": {
"name": "Chicago Bulls",
"city": "Chicago",
"abbreviation": "CHI",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/teams/{id}​

Get a specific team (v1)

Retrieve detailed information about a specific team by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the team to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "teams",
"id": "string",
"attributes": {
"name": "Chicago Bulls",
"city": "Chicago",
"abbreviation": "CHI",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
},
"included": [
{}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Team not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/teams/{id}​

Delete a team (v1)

Delete an existing team record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the team to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Team not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/teams/{id}​

Update a team (v1)

Update an existing team record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the team to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"teams"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.locationstringNoNo"Chicago"
data.attributes.mascotstringNoNo"Bulls"
data.attributes.citystringNoYes"Chicago"
data.attributes.abbreviationstringNoYes"CHI"
data.attributes.genre_idstring (uuid)NoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/teams/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"teams","id":"string","attributes":{"location":"Chicago","mascot":"Bulls","city":"Chicago","abbreviation":"CHI","genre_id":"string"}}}'

Example Response​

{
"data": {
"type": "teams",
"id": "string",
"attributes": {
"name": "Chicago Bulls",
"city": "Chicago",
"abbreviation": "CHI",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Team not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Years v1​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /v1/years​

Get all years (v1)

Retrieve a list of all years available for trading card sets

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/years" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "years",
"id": "string",
"attributes": {
"year": "1989",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
]
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

POST /v1/years​

Create a new year (v1)

Create a new year record for trading card classification

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"years"
data.attributesobjectNoNo
data.attributes.namestringYesNo"1989"
data.attributes.descriptionstringNoYes

Example Request​

curl -X POST "https://api.tradingcardapi.com/v1/years" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"years","attributes":{"name":"1989","description":"string"}}}'

Example Response​

{
"data": {
"type": "years",
"id": "string",
"attributes": {
"year": "1989",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

GET /v1/years/{id}​

Get a specific year (v1)

Retrieve detailed information about a specific year by ID

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the year to retrieve
includestringNoComma-separated list of relationships to include

Example Request​

curl -X GET "https://api.tradingcardapi.com/v1/years/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": {
"type": "years",
"id": "string",
"attributes": {
"year": "1989",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Year not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

DELETE /v1/years/{id}​

Delete a year (v1)

Delete an existing year record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the year to delete

Example Request​

curl -X DELETE "https://api.tradingcardapi.com/v1/years/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Year not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

PATCH /v1/years/{id}​

Update a year (v1)

Update an existing year record

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
idstringYesUUID of the year to update

Request Body​

Media type: application/vnd.api+json

FieldTypeRequiredNullableExampleDescription
dataobjectNoNo
data.typestringNoNo"years"
data.idstring (uuid)NoNo
data.attributesobjectNoNo
data.attributes.namestringNoNo"1989"
data.attributes.descriptionstringNoYes

Example Request​

curl -X PATCH "https://api.tradingcardapi.com/v1/years/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-H "Accept: application/vnd.api+json" \
-d '{"data":{"type":"years","id":"string","attributes":{"name":"1989","description":"string"}}}'

Example Response​

{
"data": {
"type": "years",
"id": "string",
"attributes": {
"year": "1989",
"description": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
}
}
}

Error Responses​

StatusDescription
400Bad request
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Year not found
422Unprocessable Entity — the request document failed validation. Details
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Sets v2​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

Why v2?​

The v2 checklist endpoint fixes a JSON:API semantic issue in v1:

  • v1 returns the set as primary data (data: {type: "sets"}) with cards in included - incorrect for a "checklist"
  • v2 returns cards as primary data (data: [{type: "cards"}, ...]) with set in included - correct semantics

When to use v2:

  • New integrations that want standards compliance
  • Applications prioritizing cards over set metadata
  • When you need the improved response structure

When to use v1:

  • Existing integrations (backward compatibility)
  • No breaking changes needed

Both versions are fully supported long-term.

GET /v2/sets/{set}/checklist​

Get set checklist (v2)

Retrieve the complete checklist for a trading card set. V2 returns cards as the primary data with set information in the included array. Supports compact format for large sets to avoid response size limits. Compact format returns only id, number, name, has_player and has_team fields, reducing response size by ~75%. Compact also drops the JSON:API envelope: the response omits included, per-card relationships, and per-resource links. Top-level pagination links and meta are retained. An explicit include parameter is still honored on a compact request and re-adds the corresponding included and relationships members.

Authentication: Bearer token required — send Authorization: Bearer YOUR_API_TOKEN.

Parameters​

NameTypeRequiredDescription
setstringYesUUID of the set to get checklist for
includestringNoComma-separated list of relationships to include (set,oncard,attributes). Defaults to set under the full format and to none under format=compact; see the format parameter. Passing this parameter explicitly overrides the default in both formats.
formatstringNoResponse format: 'full' returns all card fields, 'compact' returns only id, number, name, has_player and has_team. Compact additionally omits included, per-card relationships, and per-resource links; top-level pagination links and meta are retained. Pass an explicit include to re-add the corresponding envelope members.
pageintegerNoPage number for pagination (starts at 1)
per_pageintegerNoNumber of cards per page (max 100, returns all if not specified)

Example Request​

curl -X GET "https://api.tradingcardapi.com/v2/sets/{set}/checklist" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/vnd.api+json"

Example Response​

{
"data": [
{
"type": "cards",
"id": "123e4567-e89b-12d3-a456-426614174000",
"attributes": {
"name": "Michael Jordan",
"number": "23",
"serial_number": "001/100",
"image_uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Rookie Card",
"notes": "string",
"has_player": true,
"has_team": true,
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"set": {
"data": {
"type": "sets",
"id": "string"
}
},
"oncard": {
"data": [
{
"type": "string",
"id": "string"
}
]
},
"attributes": {
"data": [
{
"type": "attributes",
"id": "string"
}
]
},
"images": {
"data": [
{
"type": "card_images",
"id": "string"
}
]
}
}
}
],
"included": [
{
"type": "sets",
"id": "string",
"attributes": {
"name": "1989 Topps Baseball",
"title": "Series 1",
"description": "string",
"card_count": 792,
"current_card_count": 792,
"is_parallel": false,
"is_insert": false,
"is_autograph": false,
"is_relic": false,
"is_variation": false,
"serial": 250,
"number_prefix": "string",
"parent_set": "string",
"created_at": "string",
"updated_at": "string",
"url": "string"
},
"relationships": {
"sources": {
"data": [
{
"type": "set_sources",
"id": "string"
}
]
},
"genre": {
"data": {
"type": "genres",
"id": "string"
}
},
"manufacturer": {
"data": {
"type": "manufacturers",
"id": "string"
}
},
"brand": {
"data": {
"type": "brands",
"id": "string"
}
},
"year": {
"data": {
"type": "years",
"id": "string"
}
}
}
}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 1,
"from": 1,
"to": 25,
"per_page": 25,
"total": 100,
"last_page": 4
}
}

Error Responses​

StatusDescription
401Unauthorized
402Payment Required — the authenticated user's billing account is not subscribed (an expired trial that never converted). Details
404Set not found
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error

Version​

Unless an endpoint states otherwise, endpoints in this section are subject to the API rate limits. See the rate limits guide for quotas, response headers, and retry patterns.

GET /version​

Get API version information

Retrieve version information about the API, application, and supported versions

Authentication: Public — no API token required.

Example Request​

curl -X GET "https://api.tradingcardapi.com/version" \
-H "Accept: application/json"

Example Response​

{
"api_version": "1.0",
"app_version": "2.1.3",
"build_date": "2024-01-15",
"build_commit": "abc123def",
"supported_versions": [
"1.0",
"1.1"
],
"deprecated_versions": [
"0.9"
],
"changelog_url": "https://api.example.com/changelog"
}

Error Responses​

StatusDescription
429Too Many Requests — the caller has exhausted its rate-limit budget for the current window. Details See the rate limits guide.
500Internal server error