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.
Scopes
Every API key carries one or more scopes. A key with the wildcard scope * has access to everything.
| Scope | Grants access to |
|---|---|
| * | All scopes — full access. |
| categories:read | Read categories. |
| channels:read | Read connected channels. |
| fields:read | Read field definitions. |
| products:read | Read products (list and get). |
| products:write | Create, update, and archive products. |
Endpoints
Products
/api/v1/productsList products
Requires scope `products:read`. Paginated and filterable.
Required scope: products:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| page | query | integer — default 1 | No | |
| limit | query | integer — default 50 | No | |
| sort | query | string — default "-updated_at" | No | Column 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. |
| search | query | string | No | Case-insensitive substring match against title, sku, ean, and brand. |
| status | query | string: draft | active | archived | No | |
| include_variants | query | string: true | false | No | Set 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
}/api/v1/productsCreate 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)."
}/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (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"
}
]
}
}/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (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"
}
}/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | Yes |
Example response (200)
{
"data": {
"id": "b6b3b6a0-9b0a-4e63-8e2b-2b8f6a1d7c44",
"status": "archived"
}
}Categories
/api/v1/categoriesList categories
Requires scope `categories:read`.
Required scope: categories:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| format | query | string — 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
/api/v1/fieldsList 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
/api/v1/channelsList 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.
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": []
}
}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_..."
}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_..."
}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
}No product with this id exists in the caller's organization.
{
"error": "Unauthorized",
"message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}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": []
}
}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_..."
}Unexpected server error.
{
"error": "Unauthorized",
"message": "Missing or invalid Authorization header. Use: Bearer cc_live_..."
}