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:
200 OK:
400— missingX-Companyheader (company_id_required)401— invalid or expired token422— 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:
200 OK — ProductDetailResource:
400— missingX-Company401— invalid token422— 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:
200 OK:
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:
200 OK — ProductDetailResource:
404— product not found422— 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:
200 OK:
400— product has orders and caller lacks sufficient role404— product not found500— 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.
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:
200 OK — ProductDetailResource:
GET /2023-11/admin/products/handle/{product}
Retrieve a product by its URL handle (admin version — includes unpublished/trashed).
Path parameters:
Success response
200 OK — ProductDetailResource:
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:
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:
200 OK:
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:
200 OK — export job is queued:
401— user not authenticated422— invalidformat, invalid date range
GET /2023-11/admin/products/export/fields
List the columns available for product exports.
Request example:
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:
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:
200 OK:
400— fewer than 2 product IDs provided500— 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:
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:
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:
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 OK — CustomerResource collection:
GET /2023-11/admin/products/{product}/top-related-products
Products most frequently co-purchased with this product.
Query parameters: start_date, end_date, limit (default 5).
Success response 200 OK — ProductDetailResource 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:
200 OK — same paginated ProductListResource shape as the admin listing:
GET /2023-11/products/count
Return the total number of published products.
Request example:
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:
200 OK — ProductDetailResource:
404— product not found or not published
GET /2023-11/products/{product}
Retrieve a single published product by ULID.
Path parameters:
Success response
200 OK — ProductDetailResource:
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 OK — ProductDetailResource 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:
200 OK — ProductVariantResource:
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:
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:
200 OK — ProductVariantResource (with product relation loaded):
404— no variant with that barcode
GET /2023-11/admin/productVariants/{productVariant}
Get a single variant by ULID.
Path parameters:
Success response
200 OK — ProductVariantResource (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 OK — ProductVariantResource (with product relation loaded):
Custom Fields
Custom Fields define per-model metadata schemas. Each field is scoped to a specificmodel 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:
200 OK — array of CustomFieldResource:
POST /2023-11/admin/custom-fields
Create a new custom field definition.
Request body:
Request example:
201 Created — CustomFieldResource:
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 OK — CustomFieldResource:
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 OK — CustomFieldResource:
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 aschema (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:
201 Created — CustomObjectResource:
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 OK — CustomObjectResource:
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 fromSuccess responseschemawill delete that field’s data from all existing records via theCustomObjectRelationSynchronizer.
200 OK — CustomObjectResource:
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:
201 Created — CustomObjectRecordResource:
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 OK — CustomObjectRecordResource:
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 OK — CustomObjectRecordResource:
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 withis_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 OK — CustomObjectPublicResource:
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 Created — CustomObjectRecordPublicResource:
403— object does not allow public record creation
GET /2023-11/custom-objects/{customObject}/records/{record}
Get a single public record.
Success response 200 OK — CustomObjectRecordPublicResource:
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:
200 OK — Laravel paginator JSON (raw rows, no Resource transformation):
400— invalid table name characters403— table not in the allowed list or missing company scope404— table does not exist422— invalid filter column, invalid sort column
