Skip to main content

API Documentation

Programmatic access to your product catalog. REST, JSON, one API key — build your own integrations on top of CatalogCompass.

Getting started

1. Create an API key

In your CatalogCompass dashboard, go to Settings → API Keys and create a new API key. Copy it immediately — you won't be able to see it again.

2. Authenticate every request

Send your key as a bearer token in the Authorization header.

curl https://catalogcompass.com/api/v1/products \
  -H "Authorization: Bearer cc_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

3. Base URL

Every endpoint below is relative to this base URL.

https://catalogcompass.com

Requests and responses are JSON throughout — send Content-Type: application/json on any request with a body.

Download OpenAPI spec

Import it straight into Postman, Insomnia, or any OpenAPI 3.1-compatible tool.

Download OpenAPI spec

Scopes

Every API key carries one or more scopes. A key with the wildcard scope * has access to everything.

ScopeGrants access to
*All scopes — full access.
categories:readRead categories.
channels:readRead connected channels.
fields:readRead field definitions.
products:readRead products (list and get).
products:writeCreate, update, and archive products.

Endpoints

Products

GET/api/v1/products

List products

Requires scope `products:read`. Paginated and filterable.

Required scope: products:read

Parameters

NameInTypeRequiredDescription
pagequeryinteger — default 1No
limitqueryinteger — default 50No
sortquerystring — default "-updated_at"NoColumn to sort by, optionally prefixed with `-` for descending. One of updated_at, created_at, title, sku, brand, ean, retail_price, wholesale_price, status. Unrecognised values fall back to updated_at.
searchquerystringNoCase-insensitive substring match against title, sku, ean, and brand.
statusquerystring: draft | active | archivedNo
include_variantsquerystring: true | falseNoSet to "true" to include child variants (rows with a parentId). Default excludes them.

Example response (200)

{
  "data": [
    {
      "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
      "ean": "8712345678906",
      "sku": "WM-BLK-001",
      "title": "Wireless Ergonomic Mouse",
      "brand": "Logitech",
      "retailPrice": "24.99",
      "wholesalePrice": "14.50",
      "status": "draft",
      "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
      "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
      "condition": "NEW",
      "countryOfOrigin": "CN",
      "customFields": {
        "giftwrap_available": true
      },
      "isParent": false,
      "createdAt": "2026-06-01T09:12:00.000Z",
      "updatedAt": "2026-08-01T14:30:00.000Z"
    }
  ],
  "total": 128,
  "page": 1,
  "limit": 50
}
POST/api/v1/products

Create a product

Requires scope `products:write`. Blocked with 403 if the org's subscription is inactive or its SKU limit has been reached; blocked with 409 if the EAN is already used by another product in the org.

Required scope: products:write

Request body

{
  "title": "Wireless Ergonomic Mouse",
  "brand": "Logitech",
  "ean": "8712345678906",
  "sku": "WM-BLK-001",
  "retailPrice": "24.99",
  "wholesalePrice": "14.50",
  "wholesalePriceUsa": "15.00",
  "status": "draft",
  "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
  "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
  "condition": "NEW",
  "countryOfOrigin": "CN"
}

Example response (201)

{
  "data": {
    "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
    "orgId": "4f8e2c31-7a1d-4b9e-9c3a-1e5f8d2a6b90",
    "ean": "8712345678906",
    "sku": "WM-BLK-001",
    "title": "Wireless Ergonomic Mouse",
    "brand": "Logitech",
    "retailPrice": "24.99",
    "status": "draft",
    "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
    "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
    "wholesalePrice": "14.50",
    "wholesalePriceUsa": "15.00",
    "customFields": {
      "giftwrap_available": true
    },
    "marketplaceData": {
      "bolcom": {
        "ean": "8712345678906"
      }
    },
    "isParent": false,
    "createdAt": "2026-06-01T09:12:00.000Z",
    "updatedAt": "2026-08-01T14:30:00.000Z"
  },
  "warning": "You are approaching your plan's SKU limit (98/100 used)."
}
GET/api/v1/products/{id}

Get a product

Requires scope `products:read`. Includes the product's images and per-channel sync status.

Required scope: products:read

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yes

Example response (200)

{
  "data": {
    "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
    "orgId": "4f8e2c31-7a1d-4b9e-9c3a-1e5f8d2a6b90",
    "ean": "8712345678906",
    "sku": "WM-BLK-001",
    "title": "Wireless Ergonomic Mouse",
    "brand": "Logitech",
    "retailPrice": "24.99",
    "status": "draft",
    "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
    "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
    "wholesalePrice": "14.50",
    "wholesalePriceUsa": "15.00",
    "customFields": {
      "giftwrap_available": true
    },
    "marketplaceData": {
      "bolcom": {
        "ean": "8712345678906"
      }
    },
    "isParent": false,
    "createdAt": "2026-06-01T09:12:00.000Z",
    "updatedAt": "2026-08-01T14:30:00.000Z",
    "images": [
      {
        "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
        "cdnUrl": "https://cdn.catalogcompass.com/img/b6b3b6a0-front.jpg",
        "filename": "wireless-mouse-front.jpg",
        "position": 0,
        "altText": "Wireless mouse, front view",
        "mimeType": "image/jpeg",
        "fileSize": 184320,
        "width": 1200,
        "height": 1200
      }
    ],
    "channelStatuses": [
      {
        "channelId": "2d5a7e93-4c1b-4f6e-9a8d-3b7c1e9f0a52",
        "enabled": true,
        "syncStatus": "pending",
        "lastSyncedAt": "2026-08-05T08:00:00.000Z",
        "channelName": "bol.com",
        "channelType": "bolcom"
      }
    ]
  }
}
PUT/api/v1/products/{id}

Update a product

Requires scope `products:write`. Body fields are all optional (partial update); at least one recognised field must be present or the request is rejected with 400. Note: productType, supplier, supplierSku, costPrice, taxClass, tags, metaTitle, metaDescription, seoKeywords, and urlSlug are accepted by validation but are NOT persisted by this endpoint (not in its column allow-list) — sending them has no effect. Blocked with 403 if the org's subscription is inactive; blocked with 409 if the EAN is already used by another product in the org.

Required scope: products:write

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yes

Request body

{
  "title": "Wireless Ergonomic Mouse",
  "brand": "Logitech",
  "ean": "8712345678906",
  "sku": "WM-BLK-001",
  "retailPrice": "24.99",
  "wholesalePrice": "14.50",
  "wholesalePriceUsa": "15.00",
  "status": "draft",
  "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
  "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
  "condition": "NEW",
  "countryOfOrigin": "CN"
}

Example response (200)

{
  "data": {
    "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
    "orgId": "4f8e2c31-7a1d-4b9e-9c3a-1e5f8d2a6b90",
    "ean": "8712345678906",
    "sku": "WM-BLK-001",
    "title": "Wireless Ergonomic Mouse",
    "brand": "Logitech",
    "retailPrice": "24.99",
    "status": "draft",
    "descriptionShort": "Compact wireless mouse with USB-C fast charging.",
    "descriptionLong": "A compact, ergonomic wireless mouse with USB-C fast charging, silent clicks, and a 2.4GHz + Bluetooth dual connection.",
    "wholesalePrice": "14.50",
    "wholesalePriceUsa": "15.00",
    "customFields": {
      "giftwrap_available": true
    },
    "marketplaceData": {
      "bolcom": {
        "ean": "8712345678906"
      }
    },
    "isParent": false,
    "createdAt": "2026-06-01T09:12:00.000Z",
    "updatedAt": "2026-08-01T14:30:00.000Z"
  }
}
DELETE/api/v1/products/{id}

Archive a product

Requires scope `products:write`. This is a soft delete: the product's status is set to "archived", the row is not removed. Blocked with 403 if the org's subscription is inactive.

Required scope: products:write

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)Yes

Example response (200)

{
  "data": {
    "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
    "status": "archived"
  }
}

Categories

GET/api/v1/categories

List categories

Requires scope `categories:read`.

Required scope: categories:read

Parameters

NameInTypeRequiredDescription
formatquerystring — default "tree"No"tree" (default) nests categories under their parent via `children`. Any other value returns a flat list.

Example response (200)

{
  "data": [
    {
      "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
      "name": "Computer Accessories",
      "slug": "computer-accessories",
      "parentId": null,
      "googleProductCategory": "Electronics > Computers > Computer Accessories",
      "position": 0,
      "createdAt": "2026-06-01T09:12:00.000Z",
      "updatedAt": "2026-08-01T14:30:00.000Z",
      "children": []
    }
  ]
}

Fields

GET/api/v1/fields

List field definitions

Requires scope `fields:read`. Returns the org's mandatory, standard, and custom field definitions, plus a merged `enabled` list.

Required scope: fields:read

Example response (200)

{
  "data": {
    "mandatory": [
      {
        "key": "warrantyPeriod",
        "name": "Warranty Period",
        "type": "text",
        "category": "mandatory",
        "propertyName": "warrantyPeriod",
        "mandatory": false,
        "description": "string",
        "options": [
          "S",
          "M",
          "L"
        ],
        "gridWidth": 6
      }
    ],
    "standard": [
      {
        "key": "warrantyPeriod",
        "name": "Warranty Period",
        "type": "text",
        "category": "mandatory",
        "propertyName": "warrantyPeriod",
        "mandatory": false,
        "description": "string",
        "options": [
          "S",
          "M",
          "L"
        ],
        "gridWidth": 6,
        "enabled": true
      }
    ],
    "custom": [
      {
        "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
        "orgId": "4f8e2c31-7a1d-4b9e-9c3a-1e5f8d2a6b90",
        "name": "Warranty Period",
        "key": "warrantyPeriod",
        "fieldType": "text",
        "options": [
          "S",
          "M",
          "L"
        ],
        "defaultValue": null,
        "required": false,
        "position": 0,
        "createdAt": "2026-06-01T09:12:00.000Z",
        "updatedAt": "2026-08-01T14:30:00.000Z"
      }
    ],
    "enabled": [
      {
        "key": "warrantyPeriod",
        "name": "Warranty Period",
        "type": "text",
        "category": "mandatory",
        "propertyName": "warrantyPeriod",
        "mandatory": false,
        "description": "string",
        "options": [
          "S",
          "M",
          "L"
        ],
        "gridWidth": 6
      }
    ]
  }
}

Channels

GET/api/v1/channels

List connected channels

Requires scope `channels:read`. Read-only.

Required scope: channels:read

Example response (200)

{
  "data": [
    {
      "id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
      "type": "bolcom",
      "name": "Computer Accessories",
      "status": "active",
      "lastSyncAt": "2026-08-05T08:00:00.000Z",
      "autoSync": true,
      "syncIntervalMinutes": 60,
      "createdAt": "2026-06-01T09:12:00.000Z",
      "updatedAt": "2026-08-01T14:30:00.000Z"
    }
  ]
}

Errors

Every error response is JSON with at least an error field. Validation errors additionally include fieldErrors, keyed by field name.

400

Invalid query parameters.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_...",
  "fieldErrors": {
    "title": "Title is required"
  },
  "details": {
    "fieldErrors": {
      "title": [
        "Title is required"
      ]
    },
    "formErrors": []
  }
}
401

Missing/malformed Authorization header, unrecognised key, or an expired key. See `requireApiKey` in src/lib/auth/api-key-middleware.ts.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}
403

One of: the key is missing the required scope; the org's subscription is inactive; or the org's trial has expired.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}
403SkuLimitError

Missing scope, inactive subscription, expired trial, or the org's SKU limit has been reached (in which case the body is a SkuLimitError).

Variant: SkuLimitError — returned by POST /api/v1/products.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_...",
  "used": 98,
  "limit": 50
}
404

No product with this id exists in the caller's organization.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}
409

The given EAN already exists in the org.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_...",
  "fieldErrors": {
    "title": "Title is required"
  },
  "details": {
    "fieldErrors": {
      "title": [
        "Title is required"
      ]
    },
    "formErrors": []
  }
}
429

The key's per-minute rate limit (api_keys.rate_limit) was exceeded.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}
500

Unexpected server error.

{
  "error": "Unauthorized",
  "message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}

Ready to build?

Start your 14-day free trial and get your first API key in minutes.

Start free trial