Categories
Categories organize products into a hierarchical taxonomy (e.g. "Clothing → Tops → T-shirts"). Each product can belong to multiple categories. Categories have SEO metadata, banners, and per-channel publishing.
List categories
Returns the category tree of categories the merchant published to this channel, with the number of products in each. A category that was not published to this channel is not listed.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Query Parameters
Language code, for example he. Used only when no Accept-Language header is sent. A language the store does not support, or the store's default language, returns the default text.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Preferred language, for example he. Its first tag is used when it is one of the store's supported languages other than the default; translated fields are then returned in that language. Falls back to the locale query parameter.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/categories?locale=string" \ -H "origin: string" \ -H "accept-language: string" \ -H "X-SDK-Version: string"{
"categories": [
{
"id": "clcat_abc123",
"name": "string",
"slug": "mugs",
"parentId": null,
"image": "https://cdn.brainerce.com/categories/mugs.jpg",
"translations": {},
"children": [
{
"id": "clcat_abc123",
"name": "string",
"slug": "mugs",
"parentId": null,
"image": "https://cdn.brainerce.com/categories/mugs.jpg",
"translations": {},
"children": []
}
]
}
]
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories"
}Get category by slug (SEO landing page data)
Returns one published category by slug: name, description HTML, SEO meta, breadcrumb and product count. List its products with products?categories=<id>.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Category slug.
Query Parameters
Language code, for example he. Used only when no Accept-Language header is sent. A language the store does not support, or the store's default language, returns the default text.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Preferred language, for example he. Its first tag is used when it is one of the store's supported languages other than the default; translated fields are then returned in that language. Falls back to the locale query parameter.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/categories/slug/string?locale=string" \ -H "origin: string" \ -H "accept-language: string" \ -H "X-SDK-Version: string"{
"id": "clcat_abc123",
"name": "string",
"slug": "mugs",
"description": "string",
"metaDescription": "string",
"image": "https://cdn.brainerce.com/categories/mugs.jpg",
"breadcrumb": [
{
"name": "string",
"slug": "drinkware"
}
],
"productCount": 24
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories/slug/{slug}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories/slug/{slug}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/categories/slug/{slug}"
}List categories with pagination
Lists categories, 20 per page.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Query Parameters
true returns only active categories, false only inactive ones. Omit for both.
Only categories published on this platform code (matched against publishedOn).
Text search on the category name.
Items per page. Default 20. Maximum 100.
201 <= value <= 1001-based page number.
11 <= valuecurl -X GET "https://api.brainerce.com/api/v1/categories?isActive=true&platform=string&search=string&limit=20&page=1"{
"data": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Shoes",
"platformIds": {},
"publishedOn": [
"string"
],
"platformMetadata": {
"GOOGLE_TAXONOMY": {
"taxonomyId": 0,
"taxonomyPath": "string",
"source": "auto",
"resolvedAt": "2019-08-24T14:15:22Z"
},
"property1": {},
"property2": {}
},
"parentId": "clx1a2b3c4d5e6f7g8h9",
"slug": "shoes",
"description": "All footwear",
"metaDescription": "Shop shoes for every season",
"image": "https://cdn.example.com/categories/shoes.jpg",
"imageKey": "categories/shoes.jpg",
"isActive": true,
"taxBehavior": "taxable",
"translations": {},
"deletedAt": "2019-08-24T14:15:22Z",
"productCount": 24,
"products": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "Classic T-Shirt",
"sku": "TSHIRT-BLK-M"
}
],
"channelPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"vibeCodedPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}
],
"meta": {
"page": 1,
"limit": 20,
"total": 137,
"totalPages": 7
}
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Create a new category
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Category display name.
Store ID. See CreateBrandDto.storeId notes; resolved from auth when omitted.
Parent category ID. Omit for a root category. Categories form a tree, and depth-2 is the practical limit before the storefront filter UI degrades.
Active state. Inactive categories stay attached to products but are hidden from storefront filters.
Origin platform. Defaults to INTERNAL. Connector-sourced categories are managed by the connector and auto-deactivate on disconnect.
"INTERNAL""INTERNAL" | "SHOPIFY" | "WOOCOMMERCE" | "TIKTOK" | "META"Category banner image URL. Upload via /v1/media first.
R2/S3 object key for image above. When present, asset-deletion cascade can null this category's image automatically.
Tax inheritance. taxable (default) inherits the product's tax category; exempt overrides every product in this category to be tax-exempt regardless of the product's own setting.
"taxable""taxable" | "exempt"Merchant override for Google's numeric product taxonomy id (Merchant Center google_product_category). Omit to let the name-based auto-resolver assign one.
Long-form category copy (HTML) rendered on the storefront category landing page.
for the category page. 50-160 characters recommended.
curl -X POST "https://api.brainerce.com/api/v1/categories" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{ "name": "Headphones" }'{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Shoes",
"platformIds": {},
"publishedOn": [
"string"
],
"platformMetadata": {
"GOOGLE_TAXONOMY": {
"taxonomyId": 0,
"taxonomyPath": "string",
"source": "auto",
"resolvedAt": "2019-08-24T14:15:22Z"
},
"property1": {},
"property2": {}
},
"parentId": "clx1a2b3c4d5e6f7g8h9",
"slug": "shoes",
"description": "All footwear",
"metaDescription": "Shop shoes for every season",
"image": "https://cdn.example.com/categories/shoes.jpg",
"imageKey": "categories/shoes.jpg",
"isActive": true,
"taxBehavior": "taxable",
"translations": {},
"deletedAt": "2019-08-24T14:15:22Z",
"productCount": 24,
"products": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "Classic T-Shirt",
"sku": "TSHIRT-BLK-M"
}
],
"channelPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"vibeCodedPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Get a single category by ID
Returns one category of this store.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Category ID
curl -X GET "https://api.brainerce.com/api/v1/categories/string"{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Shoes",
"platformIds": {},
"publishedOn": [
"string"
],
"platformMetadata": {
"GOOGLE_TAXONOMY": {
"taxonomyId": 0,
"taxonomyPath": "string",
"source": "auto",
"resolvedAt": "2019-08-24T14:15:22Z"
},
"property1": {},
"property2": {}
},
"parentId": "clx1a2b3c4d5e6f7g8h9",
"slug": "shoes",
"description": "All footwear",
"metaDescription": "Shop shoes for every season",
"image": "https://cdn.example.com/categories/shoes.jpg",
"imageKey": "categories/shoes.jpg",
"isActive": true,
"taxBehavior": "taxable",
"translations": {},
"deletedAt": "2019-08-24T14:15:22Z",
"productCount": 24,
"products": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "Classic T-Shirt",
"sku": "TSHIRT-BLK-M"
}
],
"channelPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"vibeCodedPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Update a category
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Category ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255New category display name.
Parent category ID. Pass null to make this a root category.
Active state. Inactive categories stay attached to products but are hidden from storefront filters.
Category banner image URL. Upload via /v1/media first. Pass null to clear.
R2/S3 object key for image. Pass null to clear it.
Tax inheritance. taxable inherits the product's tax category; exempt makes every product in this category tax-exempt regardless of the product's own setting.
"taxable" | "exempt"Translated category fields keyed by ISO locale code. Merged into the stored translations: a locale sent here replaces that locale, other locales are kept.
Merchant override for Google's numeric product taxonomy id (Merchant Center google_product_category). A valid id pins it permanently; null clears the override and re-resolves it from the current name.
Long-form category copy (HTML) shown on the storefront category page. Pass null to clear.
<meta name="description"> for the category page. 50 to 160 characters recommended. Pass null to clear.
curl -X PATCH "https://api.brainerce.com/api/v1/categories/string" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{}'{
"id": "clx1a2b3c4d5e6f7g8h9",
"accountId": "clx1a2b3c4d5e6f7g8h9",
"storeId": "clx1a2b3c4d5e6f7g8h9",
"name": "Shoes",
"platformIds": {},
"publishedOn": [
"string"
],
"platformMetadata": {
"GOOGLE_TAXONOMY": {
"taxonomyId": 0,
"taxonomyPath": "string",
"source": "auto",
"resolvedAt": "2019-08-24T14:15:22Z"
},
"property1": {},
"property2": {}
},
"parentId": "clx1a2b3c4d5e6f7g8h9",
"slug": "shoes",
"description": "All footwear",
"metaDescription": "Shop shoes for every season",
"image": "https://cdn.example.com/categories/shoes.jpg",
"imageKey": "categories/shoes.jpg",
"isActive": true,
"taxBehavior": "taxable",
"translations": {},
"deletedAt": "2019-08-24T14:15:22Z",
"productCount": 24,
"products": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "Classic T-Shirt",
"sku": "TSHIRT-BLK-M"
}
],
"channelPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"vibeCodedPublishes": [
{
"salesChannel": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
},
"connection": {
"id": "clx1a2b3c4d5e6f7g8h9",
"name": "My storefront",
"connectionId": "vc_9f3a2b1c8d7e6f5a"
}
}
],
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Delete a category
Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Category ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255curl -X DELETE "https://api.brainerce.com/api/v1/categories/string" \ -H "Idempotency-Key: string"{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Publish a category to a sales-channel site
Makes the category available on the given sales channel (storefront). Repeating the call is harmless. A sales channel that is not part of this store, or a category that is not found, answers 404. Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Category ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Sales channel record ID or its public vc_* connection ID
curl -X POST "https://api.brainerce.com/api/v1/categories/string/publish-sales-channel" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{ "salesChannelId": "string" }'{
"success": true
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/publish-sales-channel"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/publish-sales-channel"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/publish-sales-channel"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}Unpublish a category from a sales-channel site
Removes the category from the given sales channel (storefront). Repeating the call is harmless. A sales channel that is not part of this store, or a category that is not found, answers 404. Supports Idempotency-Key header for safe retries.
Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.
In: header
Path Parameters
Category ID
Header Parameters
Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.
- Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
- Reusing a key with a different body returns
409 Conflictwithcode: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response. - Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
- Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
- Sending this header on a
GETreturns400withcode: "IDEMPOTENCY_KEY_NOT_SUPPORTED"— GETs are already idempotent. - Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.
length <= 255Sales channel record ID or its public vc_* connection ID
curl -X POST "https://api.brainerce.com/api/v1/categories/string/unpublish-sales-channel" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{ "salesChannelId": "string" }'{
"success": true
}{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or expired credential",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/unpublish-sales-channel"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/unpublish-sales-channel"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/categories/{id}/unpublish-sales-channel"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/v1/store"
}