Skip to main content

Working with Catalog

About This Section

The Catalog section allows you to manage your venue's products and categories via the Public API. You may create new categories and products, browse existing items, search by names, descriptions, and codes, and filter by specific attributes.

All operations are performed within the company context determined during authentication. You don't need to explicitly pass company_id in requests.

How a Product Is Structured in the API

A product in the system consists of two levels:

  1. Good — the general card: name, description, category, unit of measure, and VAT rate.
  2. Variations — specific sellable SKUs within the good. Each variation has its own price (default_price) and a set of codes — barcodes, SKUs, and other identifiers. A single good may contain from 1 to 150 variations.

If a good has one variation, its name field in the API response will be null — use the good-level name for display. If a good has multiple variations, each variation will have its own non-null name.

Goods available through the Public API always have business_type: "regular".

Main Scenarios

Scenario 1: Creating a Category

To organize your menu, you may consider to create a category. The category has a name, an optional description, and can be nested by providing the parent_id of an existing parent category. Maximum nesting level is 2.

Endpoint:

POST /catalog/categories

Example request body:

{
"name": "Coffee",
"description": "Hot coffee beverages",
"parent_id": null
}

If needed, you may pass external_data.id — your internal identifier from an external system. It must be unique within the company. Reusing an existing ID will result in a 409 Conflict error.

The status field is optional and defaults to active.

Scenario 2: Listing Categories

To retrieve all categories, make a paginated GET request.

Endpoint:

GET /catalog/categories

Key parameters:

ParameterDescription
statusFilter by status: active (default), inactive, or all
parent_idFilter by parent category
has_parenttrue — subcategories only, false — root categories only. Ignored if parent_id is provided
text_filterSearch by name and description (minimum 2 characters)
order_bySorting: created_at_asc, name_asc, name_desc, and others

The response contains an items array and a cursor for retrieving the next page. If cursor is null, the page is the last one.

Scenario 3: Creating a Product

To add a product, use the regular good creation endpoint.

Endpoint:

POST /catalog/goods/regular

Required fields:

  • name — product name
  • uom_id — unit of measure identifier (retrieved via GET /uoms)
  • vat.fee_item_id — VAT rate identifier (retrieved via GET /fees)
  • variations — array of 1 to 150 variations

Example request body with a single variation:

{
"name": "Cappuccino 300 ml",
"category_id": "11111111-1111-4111-8111-111111111111",
"uom_id": "33333333-3333-4333-8333-333333333333",
"vat": {
"fee_item_id": "66666666-6666-4666-8666-666666666666"
},
"variations": [
{
"status": "active",
"default_price": {
"amount": 350.00,
"currency": "RUB"
},
"codes": [
{
"type": "sku",
"value": "CAP-300-001"
}
]
}
]
}

Note: with a single variation, you can omit its name — the good-level name will be used for display.

Example with multiple variations:

{
"name": "Croissant",
"uom_id": "33333333-3333-4333-8333-333333333333",
"vat": {
"fee_item_id": "66666666-6666-4666-8666-666666666666"
},
"variations": [
{
"name": "Almond Croissant",
"status": "active",
"default_price": {
"amount": 280.00,
"currency": "RUB"
},
"codes": [
{
"type": "sku",
"value": "CRO-ALM-001"
}
]
},
{
"name": "Chocolate Croissant",
"status": "active",
"default_price": {
"amount": 300.00,
"currency": "RUB"
},
"codes": [
{
"type": "sku",
"value": "CRO-CHOC-001"
}
]
}
]
}

Up to 20 codes can be specified per variation. Supported types: ean_8, ean_13, itf_14, upc_a, sku, other.

Scenario 4: Listing Goods

Endpoint:

GET /catalog/goods/regular

Key parameters:

ParameterDescription
statusFilter by status: active (default), inactive, all
category_idFilter by one or more categories (can be passed multiple times)
has_categorytrue — goods with a category, false — goods without a category
text_filterSearch by name, description of goods and variations, and code values
order_bySorting: created_at_asc, name_asc, name_desc, and others

Important: you cannot use has_category=false together with category_id — the API will return a 400 error.

The response returns an array of goods, each containing detailed information on variations, unit of measure, and VAT rate.

Scenario 5: Retrieving a Single Good or Category

To get a specific category or good by identifier:

GET /catalog/categories/{category_id}
GET /catalog/goods/regular/{good_id}

Error Codes (Catalog-Specific)

HTTP CodeBody CodeDescription
400validation_errorRequest field validation error
400invalid_cursorInvalid or expired pagination cursor
409existing_entity_conflictConflict: duplicate external_data.id within the company