Documentation
REST API
Authenticate with a Bearer API key (created in your seller dashboard under Integrations → API Access). The reference below is generated from the live API spec, so it always matches what the backend serves. Requires a Pro or Enterprise plan.
Base URL
Bearer token authentication is required on every request.
Use this root for all authenticated REST API requests.
https://supercatch.com/api/v1Authentication Example
Include your API key in the Authorization header for every request.
curl https://supercatch.com/api/v1/listings \ -H "Authorization: Bearer YOUR_API_KEY"
API Reference
Endpoint metadata, query parameters, response fields, and examples are generated from the shared API spec.
GET/listings
List store listings
Returns non-deleted listings owned by the API key's store in newest-first order. Use pagination.nextCursor unchanged to request the next page.
Use Cases
- Sync active inventory into an ERP, warehouse tool, or marketplace feed builder.
- Audit draft, reserved, sold, and showcase listings without scraping the seller UI.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
statusOptional | string | Filters listings by lifecycle status. Omit this parameter to return every non-deleted listing status for the store. DRAFT, PENDING, PROCESSING, ACTIVE, SOLD, RESERVED, +4 more Example: |
limitOptional | integer | Maximum records to return. Values above 100 are clamped by the reader, and omitted values default to 50. Example: |
cursorOptional | string | Opaque listing id returned in pagination.nextCursor. Pass it unchanged to continue from the previous page. Example: |
Response Fields
| Field | Type | Description |
|---|---|---|
data[].id | string | Stable listing id. Use as an internal key or cursor value. Example: |
data[].slug | string | Public product/listing slug used by SuperCatch product URLs. Example: |
data[].productType | string | Catalog product family for routing and downstream taxonomy mapping. SPORTS_CARD, NONSPORTS_CARD, TCG_CARD, VIDEO_GAME, TICKET, AUTOGRAPH, +1 more Example: |
data[].status | string | Current listing lifecycle status. DRAFT, PENDING, PROCESSING, ACTIVE, SOLD, RESERVED, +4 more Example: |
data[].condition | string | Seller-facing condition or grading bucket. MINT, NEAR_MINT, EXCELLENT, GOOD, LIGHT_PLAYED, PLAYED, +2 more Example: |
data[].price | decimal-string | Base listing price as an exact decimal string. Example: |
data[].salePrice | decimal-string | null | Active sale price when one is configured; null otherwise. Example: |
data[].quantity | integer | Total quantity attached to the listing. Example: |
data[].quantityAvailable | integer | Quantity currently available for purchase after holds and sales. Example: |
data[].imageUrls | string[] | Public image URLs in display order. Example: |
data[].createdAt | date-time | ISO-8601 creation timestamp. Example: |
pagination.nextCursor | string | null | Cursor for the next page, or null when hasMore is false. Example: |
pagination.hasMore | boolean | True when another page is available. Example: |
pagination.limit | integer | Effective page size after defaulting and clamping. Example: |
Example Response
{
"data": [
{
"id": "clst_01hzn7y3d0qa9b5c2r8m4p6x7k",
"slug": "1993-topps-derek-jeter-98",
"productType": "SPORTS_CARD",
"status": "ACTIVE",
"condition": "NEAR_MINT",
"price": "49.99",
"salePrice": null,
"quantity": 1,
"quantityAvailable": 1,
"imageUrls": [
"https://supercatch.com/cdn/listings/clst_front.webp"
],
"createdAt": "2026-04-27T17:30:00.000Z"
}
],
"pagination": {
"nextCursor": "clst_01hzn7y3d0qa9b5c2r8m4p6x7k",
"hasMore": true,
"limit": 50
}
}POST/listings
Create draft listings
Pushes a batch of up to 25 cards into the API key's store as DRAFT listings owned by the store. Images are uploaded (remote URLs are re-hosted; base64 is stored to R2), catalog identity is matched, and each card lands in the seller's review queue. New drafts are grouped into a rolling batch job visible on /store/jobs (1-hour window, 500-card cap); the response jobId is pollable via GET /jobs/{jobId}. Send an Idempotency-Key header to make whole-request retries safe. Requests are rate-weighted by cards + images. Created listings are attributed to the store owner, never to a user id from the request.
Use Cases
- Push a scanning-app or external-inventory batch into the store as drafts for seller review before publishing.
- Re-run the same import safely: each card's clientId makes creation idempotent, so retries replay instead of duplicating.
- Track and review a push as a unit: returned jobId opens the batch on /store/jobs with per-card progress and counts.
Query Parameters
No query parameters.
Request Body
| Field | Type | Description |
|---|---|---|
cardsRequired | object[] | Array of card payloads to create. At least one, at most 25 per request. Excess returns a 422. Example: |
cards[].clientIdRequired | string | Caller-stable id for the card, the per-card idempotency key. While the card is still a draft, re-sending the same clientId updates that draft (status `duplicate`) instead of creating a second listing. Example: |
cards[].productTypeRequired | string | Catalog product family. Determines which identity fields are required. SPORTS_CARD, NONSPORTS_CARD, TCG_CARD, VIDEO_GAME, TICKET, AUTOGRAPH, +1 more Example: |
cards[].featuredOptional | string | Player, character, signer, or item name. Required for SPORTS_CARD, NONSPORTS_CARD, and TCG_CARD. Example: |
cards[].seriesOptional | string | Set/series name. Required for card product types. Example: |
cards[].cardNumberOptional | string | Card number within the set. Required for card product types. Example: |
cards[].yearOptional | string | Release year ("YYYY" or season "YYYY-YY"). Required for card product types. Example: |
cards[].brandOptional | string | Manufacturer. Required for card product types. Example: |
cards[].conditionOptional | string | Seller-facing condition or grading bucket for the copy. MINT, NEAR_MINT, EXCELLENT, GOOD, LIGHT_PLAYED, PLAYED, +2 more Example: |
cards[].priceOptional | number | Listing price in dollars. Optional for drafts; validated against store price bounds when present. Example: |
cards[].imageUrlsOptional | string[] | Image inputs in display order: each may be a public https URL (re-hosted to R2) or a base64 data URL (stored to R2). Max 20 per card, 100 per request. Example: |
cards[].quantityOptional | integer | Listing quantity (1-99, default 1). Unique items — graded cards and standalone autograph/memorabilia/ticket/video-game items — are always forced to 1. Example: |
cards[].sellerSkuOptional | string | Your own SKU for the copy; stored on the listing for reconciliation. Example: |
cards[].shippingProfileIdOptional | string | Id of one of your shipping profiles to attach; omit to use the store default. Example: |
Example Request
{
"cards": [
{
"clientId": "ext-row-00042",
"productType": "SPORTS_CARD",
"featured": "Derek Jeter",
"series": "Topps",
"cardNumber": "98",
"year": "1993",
"brand": "Topps",
"condition": "NEAR_MINT",
"price": 49.99,
"imageUrls": [
"https://cdn.example.com/jeter-front.jpg"
]
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
data.created | integer | Number of cards that produced a new DRAFT listing in this request. Example: |
data.failed | integer | Number of cards that could not be created (see per-card error). Example: |
data.jobId | string | null | Id of the /store/jobs batch the new drafts were grouped into (rolling 1-hour window, 500-card cap). Null when nothing new was created (e.g. all cards were idempotent duplicates or errors). Example: |
data.results | object | Per-card outcome array, aligned to the submitted cards by clientId. Example: |
data.results[].clientId | string | Echoes the submitted clientId so callers can correlate outcomes. Example: |
data.results[].status | string | created = new draft; duplicate = idempotent replay of a prior push; error = validation/creation failed. created, duplicate, error Example: |
data.results[].listingId | string | null | Created (or replayed) listing id; null when status is error. Example: |
data.results[].slug | string | null | Listing slug when created; null on error. Example: |
data.results[].listingStatus | string | null | Lifecycle status of the created listing (DRAFT for review-queue cards). DRAFT, PENDING, PROCESSING, ACTIVE, SOLD, RESERVED, +4 more Example: |
data.results[].linkedCatalog | object | null | Catalog product the card linked to or created. Present only when a catalog row was resolved at save time (existing-row link); omitted when status is error or no catalog identity was resolved yet. Example: |
data.results[].linkedCatalog.catalogId | string | Id of the linked catalog product. Example: |
data.results[].linkedCatalog.catalogType | string | Catalog target key the product belongs to. SPORTS_CARD, NONSPORTS_CARD, TCG_CARD, VIDEO_GAME, TICKET, AUTOGRAPH, +1 more Example: |
data.results[].linkedCatalog.wasExisting | boolean | True when the card linked to a catalog product that already existed; false when a new one was created for it. Example: |
data.results[].error | string | null | Human-readable failure reason when status is error; null otherwise. Example: |
Example Response
{
"data": {
"created": 1,
"failed": 0,
"jobId": "imp_01hzn7y3d0qa9b5c2r8m4p6x7k",
"results": [
{
"clientId": "ext-row-00042",
"status": "created",
"listingId": "clst_01hzn7y3d0qa9b5c2r8m4p6x7k",
"slug": "1993-topps-derek-jeter-98",
"listingStatus": "DRAFT",
"error": null
}
]
}
}GET/orders
List store orders
Returns orders owned by the API key's store in newest-first order. Use status and since filters to build incremental fulfillment or accounting imports.
Use Cases
- Pull new paid orders into shipping, accounting, or customer support systems.
- Poll recent marketplace-imported orders without giving an external system admin access.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
statusOptional | string | Filters by order lifecycle status. Omit this parameter to include all order statuses. PENDING, PAID, PROCESSING, SHIPPED, DELIVERED, CANCELLED, +2 more Example: |
sinceOptional | date-time | Filters orders whose createdAt timestamp is greater than or equal to this ISO-8601 datetime. Example: |
limitOptional | integer | Maximum records to return. Values above 100 are clamped by the reader, and omitted values default to 50. Example: |
cursorOptional | string | Opaque order id returned in pagination.nextCursor. Pass it unchanged to continue from the previous page. Example: |
Response Fields
| Field | Type | Description |
|---|---|---|
data[].id | string | Stable order id. Example: |
data[].orderNumber | string | Buyer-facing order number. Example: |
data[].storeOrderNumber | integer | Store-local numeric order sequence. Example: |
data[].status | string | Current order lifecycle status. PENDING, PAID, PROCESSING, SHIPPED, DELIVERED, CANCELLED, +2 more Example: |
data[].subtotal | decimal-string | Item subtotal before tax and shipping. Example: |
data[].shippingCost | decimal-string | Shipping amount charged to the buyer. Example: |
data[].tax | decimal-string | Tax amount collected on the order. Example: |
data[].totalAmount | decimal-string | Final charged total. Example: |
data[].trackingNumber | string | null | Carrier tracking number when shipment tracking is available. Example: |
data[].carrier | string | null | Shipping carrier label when known. Example: |
data[].sourcePlatform | string | null | Marketplace/source system that produced the order, or null for native orders. Example: |
data[].itemCount | integer | Number of line items on the order. Example: |
data[].createdAt | date-time | ISO-8601 creation timestamp. Example: |
data[].paidAt | date-time | null | Payment timestamp, or null before payment. Example: |
data[].shippedAt | date-time | null | Shipment timestamp, or null before shipment. Example: |
data[].deliveredAt | date-time | null | Delivery timestamp, or null before delivery. Example: |
data[].cancelledAt | date-time | null | Cancellation timestamp, or null unless cancelled. Example: |
pagination.nextCursor | string | null | Cursor for the next page, or null when hasMore is false. Example: |
pagination.hasMore | boolean | True when another page is available. Example: |
pagination.limit | integer | Effective page size after defaulting and clamping. Example: |
Example Response
{
"data": [
{
"id": "ord_01hzn80t0tbw67ez6j9r6p4b2m",
"orderNumber": "SC-100042",
"storeOrderNumber": 42,
"status": "PAID",
"subtotal": "49.99",
"shippingCost": "5.00",
"tax": "4.13",
"totalAmount": "59.12",
"trackingNumber": "9400111206213999999999",
"carrier": "USPS",
"sourcePlatform": "supercatch",
"itemCount": 1,
"createdAt": "2026-04-27T17:35:00.000Z",
"paidAt": "2026-04-27T17:36:00.000Z",
"shippedAt": null,
"deliveredAt": null,
"cancelledAt": null
}
],
"pagination": {
"nextCursor": "ord_01hzn80t0tbw67ez6j9r6p4b2m",
"hasMore": true,
"limit": 50
}
}POST/orders/{orderId}/ship
Mark an order shipped with tracking
Records a tracking number and carrier against one of your orders, moves it to SHIPPED, emails the buyer, and pushes the tracking back to the source marketplace where that integration supports it. Posting again for an already-shipped order is treated as a tracking correction rather than a second shipment.
Use Cases
- Push tracking back from a 3PL or warehouse system as soon as a label is generated.
- Correct a mistyped tracking number without re-notifying the buyer as a new shipment.
- Close the fulfillment loop from an external ERP so marketplace tracking stays in sync.
Query Parameters
No query parameters.
Request Body
| Field | Type | Description |
|---|---|---|
trackingNumberRequired | string | Carrier tracking number, 1-128 characters after trimming. Example: |
carrierOptional | string | Carrier name, 1-64 characters. Omit to leave the order's existing carrier unchanged. Example: |
Example Request
{
"trackingNumber": "9400111899223197428490",
"carrier": "USPS"
}Response Fields
| Field | Type | Description |
|---|---|---|
data.success | boolean | True when the order reached SHIPPED. Example: |
data.order.id | string | SuperCatch identifier for the shipped order. Example: |
data.order.status | string | Order lifecycle status after the write. Example: |
data.order.trackingNumber | string | null | Tracking number now recorded on the order. Example: |
data.order.carrier | string | null | Carrier now recorded on the order. Example: |
data.order.shippedAt | date-time | null | ISO-8601 timestamp when the order was first marked shipped. Example: |
data.platformSync | object | null | Result of pushing tracking to the source marketplace, when the order came from one. Example: |
Example Response
{
"data": {
"success": true,
"order": {
"id": "ord_01J8Z2H2Q0X7T3",
"status": "SHIPPED",
"trackingNumber": "9400111899223197428490",
"carrier": "USPS",
"shippedAt": "2026-09-02T17:41:12.000Z"
},
"platformSync": {
"synced": true,
"platform": "EBAY"
}
}
}GET/inventory
Get inventory snapshot
Returns a cached aggregate snapshot of listing counts and quantities for the API key's store. The snapshot avoids row-level image joins and is safe for dashboards.
Use Cases
- Show current inventory totals in an external operations dashboard.
- Compare sellable quantity against a warehouse or accounting system without paging every listing.
Query Parameters
No query parameters.
Response Fields
| Field | Type | Description |
|---|---|---|
data.counts | object | Listing count by ListingStatus enum value. Example: |
data.totalListings | integer | Total non-deleted listings across every status. Example: |
data.totalQuantity | integer | Sum of listing quantity across every non-deleted listing. Example: |
data.totalQuantityAvailable | integer | Sum of currently purchasable quantity after holds and sales. Example: |
data.generatedAt | date-time | ISO-8601 timestamp when the snapshot payload was generated. Example: |
Example Response
{
"data": {
"counts": {
"DRAFT": 14,
"PENDING": 2,
"PROCESSING": 0,
"ACTIVE": 128,
"SOLD": 42,
"RESERVED": 3,
"INACTIVE": 5,
"REMOVED": 0,
"REJECTED": 0,
"SHOWCASE": 9
},
"totalListings": 203,
"totalQuantity": 221,
"totalQuantityAvailable": 173,
"generatedAt": "2026-04-27T17:40:00.000Z"
}
}PATCH/inventory/quantity
Set available quantity on listings
Sets the available quantity on up to 100 of your listings in one call. Runs through the same path as a seller bulk edit, so price history is recorded and every connected marketplace channel is marked for re-sync. Listings outside an editable status are skipped and reported rather than failing the batch.
Use Cases
- Mirror stock levels from a warehouse or POS system on a schedule.
- Zero out quantity across a set of listings after selling them elsewhere.
- Restock a group of listings after a shipment arrives without touching each one by hand.
Query Parameters
No query parameters.
Request Body
| Field | Type | Description |
|---|---|---|
listingIdsRequired | string[] | Listing identifiers to update. Between 1 and 100 ids per request. Example: |
quantityRequired | integer | Absolute available quantity to set on every listed id. Between 0 and 10000; 0 takes a listing out of stock. Example: |
Example Request
{
"listingIds": [
"lst_01J8Z2H2Q0X7T3",
"lst_01J8Z2H2Q0X7T4"
],
"quantity": 3
}Response Fields
| Field | Type | Description |
|---|---|---|
data.updated | integer | Number of listings that took the new quantity. Example: |
data.skipped | integer | Number of listings filtered out before the write. Example: |
data.quantity | integer | Absolute quantity that was applied, echoed back. Example: |
data.rejections | object | Per-listing skip reasons, such as a status outside the editable set. Empty when every id was updated. Example: |
Example Response
{
"data": {
"updated": 2,
"skipped": 1,
"quantity": 3,
"rejections": [
{
"listingId": "lst_01J8Z2H2Q0X7T5",
"reason": "status_not_editable"
}
]
}
}GET/jobs/{jobId}
Get push/import job status
Returns the status and per-card counts of one of the store's batch jobs, including the API-push job returned by POST /listings. Poll it to confirm a push landed and how many cards were created; the cards themselves are reviewable on /store/jobs.
Use Cases
- Poll the jobId returned by POST /listings to confirm the batch landed and read its counts.
- Drive an external dashboard from push/import job progress without scraping the seller UI.
Query Parameters
No query parameters.
Response Fields
| Field | Type | Description |
|---|---|---|
data.id | string | Job id (matches the jobId from POST /listings). Example: |
data.name | string | null | Seller-facing job label. Example: |
data.status | string | Job lifecycle status (COMPLETED for synchronous API pushes). Example: |
data.totalItems | integer | Total cards grouped into the job. Example: |
data.successfulItems | integer | Cards that produced a listing. Example: |
data.failedItems | integer | Cards that failed to create. Example: |
data.createdAt | date-time | ISO-8601 job creation timestamp. Example: |
data.completedAt | date-time | null | ISO-8601 completion timestamp; null while still open. Example: |
Example Response
{
"data": {
"id": "imp_01hzn7y3d0qa9b5c2r8m4p6x7k",
"name": "API push — 12 cards",
"status": "COMPLETED",
"totalItems": 12,
"successfulItems": 12,
"failedItems": 0,
"createdAt": "2026-04-27T17:30:00.000Z",
"completedAt": "2026-04-27T17:30:05.000Z"
}
}GET/analytics
Get sales and traffic analytics
Returns a per-day views/sales/revenue series for the API key's store plus window totals and derived rates. Aggregated from the seller daily snapshots, so it is cheap enough to poll on a dashboard refresh.
Use Cases
- Chart store revenue and conversion in an external BI tool or spreadsheet.
- Reconcile marketplace payouts against on-platform sales for a reporting period.
- Alert when daily sales fall below a threshold without scraping the seller dashboard.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
daysOptional | integer | Length of the reporting window in days, counting back from today. Defaults to 30 and is capped at 365. Example: |
Response Fields
| Field | Type | Description |
|---|---|---|
data.windowDays | integer | Reporting window actually applied after clamping to the 1-365 range. Example: |
data.daily[].date | date-time | UTC midnight ISO-8601 timestamp identifying the day. Example: |
data.daily[].views | integer | Listing detail views recorded for the store that day. Example: |
data.daily[].sales | integer | Units sold that day across on-site and imported marketplace orders. Example: |
data.daily[].revenue | decimal-string | Gross revenue in USD for that day before fees. Example: |
data.daily[].newListings | integer | Listings first published by the store that day. Example: |
data.totals.views | integer | Sum of listing views across the window. Example: |
data.totals.sales | integer | Sum of units sold across the window. Example: |
data.totals.revenue | decimal-string | Sum of gross revenue in USD across the window. Example: |
data.totals.newListings | integer | Listings first published across the window. Example: |
data.totals.avgSalePrice | decimal-string | Window revenue divided by window units sold, in USD. Example: |
data.avgDailyRevenue | decimal-string | Window revenue divided by `windowDays`, in USD. Example: |
data.avgDailySales | decimal-string | Window units sold divided by `windowDays`. Example: |
data.conversionRate | decimal-string | Units sold as a percentage of listing views across the window. Example: |
data.generatedAt | date-time | ISO-8601 timestamp when the payload was generated. Example: |
Example Response
{
"data": {
"windowDays": 30,
"daily": [
{
"date": "2026-08-14T00:00:00.000Z",
"views": 412,
"sales": 7,
"revenue": "318.45",
"newListings": 12
}
],
"totals": {
"views": 11480,
"sales": 168,
"revenue": "7622.90",
"newListings": 240,
"avgSalePrice": "45.37"
},
"avgDailyRevenue": "254.10",
"avgDailySales": "5.60",
"conversionRate": "1.46",
"generatedAt": "2026-09-02T17:40:00.000Z"
}
}Rate Limits
Hourly request caps are enforced per API key. Rate limit headers are returned with every API response.
Pro Plan
1,000 requests/hour
Enterprise Plan
10,000 requests/hour
Free and starter plans do not include REST API access. Upgrade to pro or enterprise to enable API keys. Contact support for custom enterprise limits.
