Skip to main content
The Catalog domain manages the full product lifecycle: physical goods, digital items, and bookable services. Each Product may have multiple Variants (SKU-level records) and Options (size, color, etc.). The domain also exposes Custom Fields (per-model metadata schema definitions), Custom Objects (freeform data schemas with typed fields), and a generic Table Model query endpoint for direct table access. There are two route groups: 2023-11/admin/… (authenticated, requires X-Company) and 2023-11/… (public, scoped to a storefront via X-Shop). Base URL https://api.genuka.com · Auth Authorization: Bearer <token> + X-Company: <companyId> · See Getting Started for shared conventions, pagination & error formats.

Endpoints at a glance


Products (Admin)

GET /2023-11/admin/products

List products for the authenticated company with rich filtering, sorting, and include support. Query parameters: Request example:
Success response 200 OK:
Errors:
  • 400 — missing X-Company header (company_id_required)
  • 401 — invalid or expired token
  • 422 — invalid filter/sort column

POST /2023-11/admin/products

Create a new product (physical good or service). Variants and options can be embedded in the same request. Request body: Variant object fields: Request example:
Success response 200 OKProductDetailResource:
Errors:
  • 400 — missing X-Company
  • 401 — invalid token
  • 422 — validation failure

GET /2023-11/admin/products/{product}

Retrieve a single product by ULID. Includes soft-deleted products. Passing ?analytics=true switches the response to the aggregated analytics payload. Path parameters: Query parameters: Request example:
Success response 200 OK:
Errors:
  • 404 — product not found

PUT /2023-11/admin/products/{product}

Full update of a product. The request body mirrors the create body; variants and options embedded in the payload are upserted by ID. Path parameters: Request body (all fields optional — omitted fields retain their current values): Request example:
Success response 200 OKProductDetailResource:
Errors:
  • 404 — product not found
  • 422 — validation failure

DELETE /2023-11/admin/products/{product}

Soft-delete a product. Products with orders can only be deleted by a manager, admin, or superadmin role. Pass ?soft=true to skip the order-count guard. Path parameters: Query parameters: Request example:
Success response 200 OK:
Errors:
  • 400 — product has orders and caller lacks sufficient role
  • 404 — product not found
  • 500 — unexpected error

POST /2023-11/admin/products/{product}/restore

Restore a soft-deleted product. Path parameters: Request example: Request body: None — no body required for this action endpoint.
Success response 200 OK:

PUT /2023-11/admin/products/{product}/{field}

Update a single field on a product without a full body. Special handling exists for shops (syncs pivot) and published (toggles boolean). Path parameters: Request body: Request example:
Success response 200 OKProductDetailResource:

GET /2023-11/admin/products/handle/{product}

Retrieve a product by its URL handle (admin version — includes unpublished/trashed). Path parameters: Success response 200 OKProductDetailResource:
Errors:
  • 404 — no product found with that handle

GET /2023-11/admin/products/{product}/analytics

Return aggregated analytics for a product: top customers, total orders, total sales value, total quantity sold, top shops, and top related products. Path parameters: Query parameters: Request example:
Success response 200 OK:

POST /2023-11/admin/products/bulk-assign-professionals

Bulk-assign one or more professionals to the services of multiple products. Request body: Request example:
Success response 200 OK:
Errors:
  • 422 — invalid product/professional IDs

POST /2023-11/admin/products/export

Trigger an asynchronous product export. The file is generated in the background and the user is notified on completion. Request body: Request example:
Success response 200 OK — export job is queued:
Errors:
  • 401 — user not authenticated
  • 422 — invalid format, invalid date range

GET /2023-11/admin/products/export/fields

List the columns available for product exports. Request example:
Success response 200 OK:

POST /2023-11/admin/products/import

Import products from an Excel or CSV file. Processing is asynchronous; the user is notified when complete. Request body (multipart/form-data): Request example:
Success response 200 OK:

POST /2023-11/admin/products/import-chunk

Upload a single chunk of a large import file. Chunks are stored temporarily in S3 and later merged with merge-chunk. Request body (multipart/form-data): Success response 200 OK:

POST /2023-11/admin/products/merge-chunk

Merge all uploaded chunks into a final file and dispatch the import job. Request body: Success response 200 OK:

POST /2023-11/admin/products/merge

Merge multiple products into a single canonical product, transferring orders, collections, tags, shops, stocks, variants, and media. Request body: Request example:
Success response 200 OK:
Errors:
  • 400 — fewer than 2 product IDs provided
  • 500 — merge transaction failed

POST /2023-11/admin/products/migration

Create a product for data migration purposes (bypasses normal upsert process, sets exact timestamps). Request body: Success response 200 OK — raw Product model JSON:

POST /2023-11/admin/products/migration/{product}/options

Create an option on a migration product. Identical behavior to POST /2023-11/admin/products/{product}/options. Path parameters: Request body: Success response 200 OK — raw ProductOption JSON:

POST /2023-11/admin/products/migration/{product}/variants

Create a variant on a migration product. Identical behavior to POST /2023-11/admin/products/{product}/variants. Path parameters: Request body: Success response 200 OK — raw ProductVariant JSON:

POST /2023-11/admin/products/{product}/options

Create a product option (e.g. Size, Color) with its allowed values. Path parameters: Request body: Request example:
Success response 200 OK — raw ProductOption JSON:

POST /2023-11/admin/products/{product}/variants

Create a new variant for a product. Path parameters: Request body: Request example:
Success response 200 OK — raw ProductVariant JSON:

Products — Analytics

GET /2023-11/admin/products/{product}/sales

Revenue time-series for a product, with optional comparison period. Path parameters: Query parameters: Request example:
Success response 200 OK:

GET /2023-11/admin/products/{product}/quantity-sold

Units-sold time-series for a product with comparison period. Same query parameters as /sales, but data values are integer quantities. Path parameters: same as /sales. Query parameters: same as /sales. Success response 200 OK:

GET /2023-11/admin/products/{product}/sales-by-shop

Total revenue grouped by shop for a given period. Path parameters: Query parameters: Success response 200 OK:

GET /2023-11/admin/products/{product}/sales-by-gender

Sales revenue grouped by customer gender. Query parameters: start_date, end_date. Success response 200 OK:

GET /2023-11/admin/products/{product}/sales-by-type-of-customer

Sales revenue grouped by customer type. Query parameters: start_date, end_date. Success response 200 OK:

GET /2023-11/admin/products/{product}/global-rank

The product’s sales rank among all company products for the given period. Query parameters: start_date, end_date. Success response 200 OK:

GET /2023-11/admin/products/{product}/rank-in-shops

Per-shop sales rank of the product. Returns a map of shop ULID to integer rank position. Query parameters: start_date, end_date. Success response 200 OK:

GET /2023-11/admin/products/{product}/details-by-shops

Revenue, profit, production cost, and quantity sold broken down per shop. Query parameters: start_date, end_date. Success response 200 OK:

GET /2023-11/admin/products/{product}/top-customers

Top customers ranked by spend on this product. Query parameters: Success response 200 OKCustomerResource collection:

Products most frequently co-purchased with this product. Query parameters: start_date, end_date, limit (default 5). Success response 200 OKProductDetailResource collection:

Products (Public)

GET /2023-11/products

Public product listing. Scoped to the storefront identified by X-Shop. Supports the same filtering and sorting as the admin list. Public users cannot search by SKU, and metadata.downloadable_link is stripped from the response. Query parameters are identical to the admin listing. The X-Company header is required; X-Shop is optional but recommended for shop-scoped results. Request example:
Success response 200 OK — same paginated ProductListResource shape as the admin listing:

GET /2023-11/products/count

Return the total number of published products. Request example:
Success response 200 OK:

GET /2023-11/products/handle/{handle}

Retrieve a published product by its URL handle. Result is cached for 24 hours. Path parameters: Request example:
Success response 200 OKProductDetailResource:
Errors:
  • 404 — product not found or not published

GET /2023-11/products/{product}

Retrieve a single published product by ULID. Path parameters: Success response 200 OKProductDetailResource:
Errors:
  • 404 — product not found or not published

GET /2023-11/products/handle/{product}/similar

GET /2023-11/products/{product}/similar

Return similar products for a given product (by handle or ULID). Results are cached for 30 minutes. The algorithm tries co-purchased products first, then same-collection products, then same-price-range products, then random products. Query parameters: Success response 200 OKProductDetailResource collection:

GET /2023-11/products/{product}/variants/{variant}

Get a specific variant of a product. Optionally check live stock availability. Path parameters: Query parameters: Request example:
Success response 200 OKProductVariantResource:
Errors:
  • 404 — product or variant not found, or variant does not belong to product

Product Variants (Admin)

GET /2023-11/admin/productVariants

List all product variants for the company. Query parameters: Request example:
Success response 200 OK — paginated ProductVariantResource collection. The variant resource includes:

GET /2023-11/admin/productVariants/barcode/{barcode}

Look up a variant by exact barcode. Returns 404 if not found. Path parameters: Request example:
Success response 200 OKProductVariantResource (with product relation loaded):
Errors:
  • 404 — no variant with that barcode

GET /2023-11/admin/productVariants/{productVariant}

Get a single variant by ULID. Path parameters: Success response 200 OKProductVariantResource (with product relation loaded):

Product Variants (Public)

GET /2023-11/productVariants

Public variant listing. Same query parameters as the admin version. Success response 200 OK — paginated ProductVariantResource collection (metadata.downloadable_link is stripped for public users):

GET /2023-11/productVariants/{productVariant}

Get a single variant by ULID (public). Path parameters: Success response 200 OKProductVariantResource (with product relation loaded):

Custom Fields

Custom Fields define per-model metadata schemas. Each field is scoped to a specific model string (e.g. products, customers) and a company_id.

GET /2023-11/admin/custom-fields

List all custom field definitions for the company. Query parameters: Request example:
Success response 200 OK — array of CustomFieldResource:

POST /2023-11/admin/custom-fields

Create a new custom field definition. Request body: Request example:
Success response 201 CreatedCustomFieldResource:
Errors:
  • 422 — key already exists for this model, invalid type, missing required fields

GET /2023-11/admin/custom-fields/{customField}

Get a single custom field definition. Path parameters: Success response 200 OKCustomFieldResource:

PUT /2023-11/admin/custom-fields/{customField}

Update a custom field definition. All fields are optional (partial update via sometimes rules). Path parameters: same as GET. Request body (all fields optional): Success response 200 OKCustomFieldResource:

DELETE /2023-11/admin/custom-fields/{customField}

Delete a custom field definition. Path parameters: same as GET. Success response 204 No Content — no body.

Custom Objects (Admin)

Custom Objects are user-defined data schemas with typed field definitions. Each object has a schema (array of field definitions) and stores data in records.

GET /2023-11/admin/custom-objects

List all custom object schemas for the company. Query parameters: Success response 200 OK — array of CustomObjectResource:

POST /2023-11/admin/custom-objects

Create a new custom object schema. Request body: Schema item fields: Request example:
Success response 201 CreatedCustomObjectResource:
Errors:
  • 422 — duplicate key, invalid field type, duplicate schema keys

GET /2023-11/admin/custom-objects/{customObject}

Get a single custom object schema (includes records_count). Path parameters: Success response 200 OKCustomObjectResource:

PUT /2023-11/admin/custom-objects/{customObject}

Update a custom object schema. When schema fields are removed, related record data for those fields is pruned. Path parameters: same as GET. Request body (all fields optional):
Note: Removing a field from schema will delete that field’s data from all existing records via the CustomObjectRelationSynchronizer.
Success response 200 OKCustomObjectResource:

DELETE /2023-11/admin/custom-objects/{customObject}

Delete a custom object schema and all its records. Success response 204 No Content — no body.

Custom Object Records (Admin)

GET /2023-11/admin/custom-objects/{customObject}/records

List records belonging to a custom object. Path parameters: Query parameters: Success response 200 OK — paginated CustomObjectRecordResource:

POST /2023-11/admin/custom-objects/{customObject}/records

Create a new record in a custom object. data is validated against the schema field rules at creation time. Path parameters: Request body: Request example:
Success response 201 CreatedCustomObjectRecordResource:
Errors:
  • 422 — data does not satisfy schema validation rules

GET /2023-11/admin/custom-objects/{customObject}/records/{record}

Get a single record (with customObject relation loaded). Path parameters: Success response 200 OKCustomObjectRecordResource:
Errors:
  • 404 — record does not belong to this custom object

PUT /2023-11/admin/custom-objects/{customObject}/records/{record}

Update a record. Omitting data from the request body preserves existing field values. Path parameters: same as GET. Request body: Success response 200 OKCustomObjectRecordResource:

DELETE /2023-11/admin/custom-objects/{customObject}/records/{record}

Delete a record and prune its relation references. Success response 204 No Content — no body.

Custom Objects (Public)

Only objects with is_public: true are accessible via the public endpoints. Internal fields (settings, app_id, company_id) are hidden. Record data is filtered to is_public: true schema fields only.

GET /2023-11/custom-objects

List public custom object schemas. Query parameters: X-Company required; no auth token needed. Success response 200 OK — array of CustomObjectPublicResource:

GET /2023-11/custom-objects/{customObject}

Get a single public custom object. Success response 200 OKCustomObjectPublicResource:
Errors:
  • 404 — object not found or not public

GET /2023-11/custom-objects/{customObject}/records

List records of a public custom object. Query parameters: Success response 200 OK — paginated CustomObjectRecordPublicResource:

POST /2023-11/custom-objects/{customObject}/records

Create a record in a public custom object. Requires allow_public_create: true on the object. Data is validated against the public-writable schema fields only. Request body: Success response 201 CreatedCustomObjectRecordPublicResource:
Errors:
  • 403 — object does not allow public record creation

GET /2023-11/custom-objects/{customObject}/records/{record}

Get a single public record. Success response 200 OKCustomObjectRecordPublicResource:

Table Model

GET /2023-11/admin/table_models/{table}

Generic paginated query against an allowed database table. All results are scoped to the authenticated company (via company_id column or a configured through join). Path parameters: Query parameters: Request example:
Success response 200 OK — Laravel paginator JSON (raw rows, no Resource transformation):
Errors:
  • 400 — invalid table name characters
  • 403 — table not in the allowed list or missing company scope
  • 404 — table does not exist
  • 422 — invalid filter column, invalid sort column