{"openapi":"3.0.0","paths":{"/merchant/v1/products":{"get":{"description":"Lists products of the shop with filtering and pagination.","operationId":"MerchantProductsController_listProducts","parameters":[{"name":"status","required":false,"in":"query","description":"Filter by product status (comma-separated for multi-select, e.g. ACTIVE,DRAFT)","schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductStatus"}}},{"name":"search","required":false,"in":"query","description":"Search by product name, slug or SKU","schema":{"type":"string"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by category ID","schema":{"format":"uuid","type":"string"}},{"name":"isActive","required":false,"in":"query","description":"Filter by active flag","schema":{"type":"boolean"}},{"name":"includeVariants","required":false,"in":"query","description":"Include variants in the response","schema":{"default":false,"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantProductOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/SortDirection"}}],"responses":{"200":{"description":"Products matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductListResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List products","tags":["Merchant API - Products"]},"post":{"operationId":"MerchantProductsController_createProduct","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"201":{"description":"Product created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a product","tags":["Merchant API - Products"]}},"/merchant/v1/products/{productId}":{"get":{"operationId":"MerchantProductsController_getProduct","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Product found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponseDto"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a product by ID","tags":["Merchant API - Products"]},"patch":{"operationId":"MerchantProductsController_updateProduct","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":"Product updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponseDto"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a product","tags":["Merchant API - Products"]},"delete":{"description":"Soft delete — the product disappears from the catalog.","operationId":"MerchantProductsController_deleteProduct","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Product deleted"},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a product","tags":["Merchant API - Products"]}},"/merchant/v1/orders":{"get":{"description":"Lists orders of the shop with filtering and pagination.","operationId":"MerchantOrdersController_listOrders","parameters":[{"name":"status","required":false,"in":"query","description":"Filter by order status (comma-separated for multi-select, e.g. PENDING,CONFIRMED)","schema":{"type":"array","items":{"$ref":"#/components/schemas/OrderStatus"}}},{"name":"paymentStatus","required":false,"in":"query","description":"Filter by payment status (comma-separated for multi-select, e.g. PAID,PENDING)","schema":{"type":"array","items":{"$ref":"#/components/schemas/PaymentStatus"}}},{"name":"fulfillmentStatus","required":false,"in":"query","description":"Filter by fulfillment status (comma-separated for multi-select, e.g. UNFULFILLED,IN_TRANSIT)","schema":{"type":"array","items":{"$ref":"#/components/schemas/FulfillmentStatus"}}},{"name":"customerId","required":false,"in":"query","description":"Filter by customer ID","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Search across the order number, the buyer e-mail, name and phone, and the name / company / city / street of both addresses. A single member of an identifier matches on its own — `0002` finds `ORD-20260711-0002`. Several words all have to match (in any field); `\"exact phrase\"`, `-excluded`, `OR` and field narrowing (`email:`, `tel:`, `nr:`, `sku:`, `nip:`, `id:`) are supported.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max items to return","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination","schema":{"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","description":"Sort field. `relevance` orders by how well each order matches `search`; without a search term it falls back to the newest first.","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","total","orderNumber","relevance"]}},{"name":"orderDir","required":false,"in":"query","description":"Sort direction","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"tags","required":false,"in":"query","description":"Comma-separated tags (OR logic — matches orders with ANY of the specified tags)","schema":{"type":"array","items":{"type":"string"}}},{"name":"isArchived","required":false,"in":"query","description":"Filter by archive status: true/false","schema":{"type":"boolean"}},{"name":"withImportedLinesToSettle","required":false,"in":"query","description":"true = only imported orders whose unshipped lines add up exactly to the amount the previous shop left out of the imported subtotal (lines it cancelled before shipping), which can still be settled and keep at least one line.","schema":{"type":"boolean"}},{"name":"dateFrom","required":false,"in":"query","description":"Filter from date (ISO 8601)","schema":{"example":"2024-01-01","type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"Filter to date (ISO 8601)","schema":{"example":"2024-12-31","type":"string"}}],"responses":{"200":{"description":"Orders matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderListAdminResponseDto"}}}},"400":{"description":"Invalid date range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List orders","tags":["Merchant API - Orders"]}},"/merchant/v1/orders/{orderId}":{"get":{"operationId":"MerchantOrdersController_getOrder","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Order found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponseDto"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get an order by ID","tags":["Merchant API - Orders"]}},"/merchant/v1/orders/{orderId}/status":{"patch":{"description":"Transitions the order status — the order state machine validates the transition.","operationId":"MerchantOrdersController_updateStatus","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderStatusDto"}}}},"responses":{"200":{"description":"Order status updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponseDto"}}}},"400":{"description":"Invalid status transition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update order status","tags":["Merchant API - Orders"]}},"/merchant/v1/orders/{orderId}/fulfillment-status":{"patch":{"operationId":"MerchantOrdersController_updateFulfillmentStatus","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFulfillmentStatusDto"}}}},"responses":{"200":{"description":"Fulfillment status updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponseDto"}}}},"400":{"description":"Invalid fulfillment transition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update fulfillment status","tags":["Merchant API - Orders"]}},"/merchant/v1/orders/{orderId}/cancel":{"post":{"description":"Cancels the order with an optional reason.","operationId":"MerchantOrdersController_cancelOrder","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelOrderDto"}}}},"responses":{"200":{"description":"Order cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponseDto"}}}},"400":{"description":"Cannot cancel order in current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Cancel an order","tags":["Merchant API - Orders"]}},"/merchant/v1/orders/{orderId}/tags":{"patch":{"operationId":"MerchantOrdersController_updateTags","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagsDto"}}}},"responses":{"200":{"description":"Tags updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponseDto"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Replace order tags","tags":["Merchant API - Orders"]}},"/merchant/v1/customers":{"get":{"description":"Lists customers of the shop with filtering and pagination.","operationId":"MerchantCustomersController_listCustomers","parameters":[{"name":"status","required":false,"in":"query","description":"Filter by customer status","schema":{"$ref":"#/components/schemas/CustomerStatus"}},{"name":"search","required":false,"in":"query","description":"Search by email, name or phone","schema":{"type":"string"}},{"name":"isGuest","required":false,"in":"query","description":"Filter by guest flag","schema":{"type":"boolean"}},{"name":"hasOrders","required":false,"in":"query","description":"Only customers with at least one order","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantCustomerOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/SortDirection"}}],"responses":{"200":{"description":"Customers matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerListResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List customers","tags":["Merchant API - Customers"]},"post":{"operationId":"MerchantCustomersController_createCustomer","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCreateCustomerDto"}}}},"responses":{"201":{"description":"Customer created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a customer","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/{customerId}":{"get":{"operationId":"MerchantCustomersController_getCustomer","parameters":[{"name":"customerId","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Customer found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a customer by ID","tags":["Merchant API - Customers"]},"patch":{"operationId":"MerchantCustomersController_updateCustomer","parameters":[{"name":"customerId","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerDto"}}}},"responses":{"200":{"description":"Customer updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a customer","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/{customerId}/orders":{"get":{"description":"Requires the orders.read permission (order data, not customer data).","operationId":"MerchantCustomersController_listCustomerOrders","parameters":[{"name":"customerId","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"Orders of the customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderListAdminResponseDto"}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List a customer's orders","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/bulk-delete/preview":{"post":{"description":"Counts how many import-sourced customers will be permanently deleted vs skipped (have history). No mutation.","operationId":"MerchantCustomersController_previewBulkDelete","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantBulkDeleteCustomersDto"}}}},"responses":{"200":{"description":"Deletion preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeletePreviewDto"}}}}},"security":[{"api-key":[]}],"summary":"Preview bulk hard-delete","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/bulk-delete":{"post":{"description":"Permanently deletes import-sourced customers with no order/return/review/loyalty/referral history. Customers with history are skipped (use the merchant dashboard to anonymize). Returns a job to poll.","operationId":"MerchantCustomersController_bulkDeleteCustomers","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantBulkDeleteCustomersDto"}}}},"responses":{"202":{"description":"Deletion job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDeletionJobResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Bulk hard-delete eligible import customers (async)","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/bulk-delete/{jobId}/status":{"get":{"operationId":"MerchantCustomersController_getBulkDeleteStatus","parameters":[{"name":"jobId","required":true,"in":"path","description":"Deletion job ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion job status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDeletionJobResponseDto"}}}},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get bulk deletion job status","tags":["Merchant API - Customers"]}},"/merchant/v1/customers/bulk-delete/{jobId}/cancel":{"post":{"operationId":"MerchantCustomersController_cancelBulkDelete","parameters":[{"name":"jobId","required":true,"in":"path","description":"Deletion job ID","schema":{"type":"string"}}],"responses":{"202":{"description":"Cancellation accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDeletionJobResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Cancel a bulk deletion job","tags":["Merchant API - Customers"]}},"/merchant/v1/inventory/variants":{"get":{"operationId":"MerchantInventoryController_listVariants","parameters":[{"name":"search","required":false,"in":"query","description":"Search by product name, variant name or SKU","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"maximum":10000,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Sort field. `createdAt` and `updatedAt` describe the VARIANT: when it was added and when it was last edited (catalogue fields, option links, attributes or a manual stock correction). Sales and cart reservations never move `updatedAt`, so it is safe as an incremental-sync cursor for catalogue changes.","schema":{"$ref":"#/components/schemas/MerchantInventorySortBy"}},{"name":"sortOrder","required":false,"in":"query","schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"locationId","required":false,"in":"query","description":"Filter stock values by location ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Variants with stock info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryVariantsPagedResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List variants with stock info","tags":["Merchant API - Inventory"]}},"/merchant/v1/inventory/ledger":{"get":{"operationId":"MerchantInventoryController_getLedger","parameters":[{"name":"locationId","required":false,"in":"query","description":"Filter by location ID","schema":{"format":"uuid","type":"string"}},{"name":"operationType","required":false,"in":"query","description":"Filter by operation types (comma-separated)","schema":{"type":"string"}},{"name":"dateFrom","required":false,"in":"query","description":"Filter from date (ISO 8601)","schema":{"format":"date-time","type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"Filter to date (ISO 8601)","schema":{"format":"date-time","type":"string"}},{"name":"search","required":false,"in":"query","description":"Search by product name or SKU","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"maximum":10000,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}}],"responses":{"200":{"description":"Paginated shop-wide ledger entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopLedgerResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get the shop-wide inventory ledger (audit trail) with filters","tags":["Merchant API - Inventory"]}},"/merchant/v1/inventory/variants/{variantId}":{"get":{"operationId":"MerchantInventoryController_getStock","parameters":[{"name":"variantId","required":true,"in":"path","description":"Variant ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Stock information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockInfoResponseDto"}}}},"404":{"description":"Variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get stock for a variant","tags":["Merchant API - Inventory"]}},"/merchant/v1/inventory/variants/{variantId}/adjust":{"post":{"description":"Increase, decrease or set the stock level. The adjustment lands in the inventory ledger.","operationId":"MerchantInventoryController_adjustStock","parameters":[{"name":"variantId","required":true,"in":"path","description":"Variant ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustStockDto"}}}},"responses":{"200":{"description":"Stock adjusted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockAdjustmentResultResponseDto"}}}},"400":{"description":"Invalid adjustment (e.g., negative stock)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Concurrent modification conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Adjust stock for a variant","tags":["Merchant API - Inventory"]}},"/merchant/v1/brands":{"get":{"description":"Lists brands of the shop with search and pagination.","operationId":"MerchantBrandsController_listBrands","parameters":[{"name":"search","required":false,"in":"query","description":"Search brands by name","schema":{"type":"string"}},{"name":"isActive","required":false,"in":"query","description":"Filter by active flag","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantBrandOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/SortDirection"}}],"responses":{"200":{"description":"Brands matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedBrandResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List brands","tags":["Merchant API - Brands"]},"post":{"operationId":"MerchantBrandsController_createBrand","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBrandDto"}}}},"responses":{"201":{"description":"Brand created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a brand","tags":["Merchant API - Brands"]}},"/merchant/v1/brands/{brandId}":{"get":{"operationId":"MerchantBrandsController_getBrand","parameters":[{"name":"brandId","required":true,"in":"path","description":"Brand ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Brand found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponseDto"}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a brand by ID","tags":["Merchant API - Brands"]},"patch":{"operationId":"MerchantBrandsController_updateBrand","parameters":[{"name":"brandId","required":true,"in":"path","description":"Brand ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBrandDto"}}}},"responses":{"200":{"description":"Brand updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponseDto"}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a brand","tags":["Merchant API - Brands"]},"delete":{"description":"Deletes the brand. Products assigned to it keep existing with no brand (disassociated, not removed).","operationId":"MerchantBrandsController_deleteBrand","parameters":[{"name":"brandId","required":true,"in":"path","description":"Brand ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Brand deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandDeleteResultDto"}}}},"404":{"description":"Brand not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a brand","tags":["Merchant API - Brands"]}},"/merchant/v1/products/{productId}/variants":{"get":{"operationId":"MerchantVariantsController_listVariants","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Variants of the product","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariantResponseDto"}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List variants of a product","tags":["Merchant API - Product Variants"]},"post":{"operationId":"MerchantVariantsController_createVariant","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductVariantDto"}}}},"responses":{"201":{"description":"Variant created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductVariantResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"SKU already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a variant for a product","tags":["Merchant API - Product Variants"]}},"/merchant/v1/variants/{variantId}":{"get":{"operationId":"MerchantVariantsController_getVariant","parameters":[{"name":"variantId","required":true,"in":"path","description":"Variant ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Variant found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductVariantResponseDto"}}}},"404":{"description":"Variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a variant by ID","tags":["Merchant API - Product Variants"]},"patch":{"operationId":"MerchantVariantsController_updateVariant","parameters":[{"name":"variantId","required":true,"in":"path","description":"Variant ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductVariantDto"}}}},"responses":{"200":{"description":"Variant updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductVariantResponseDto"}}}},"404":{"description":"Variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"SKU already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a variant","tags":["Merchant API - Product Variants"]},"delete":{"description":"Soft delete. If the default variant is removed, another active variant is promoted automatically.","operationId":"MerchantVariantsController_deleteVariant","parameters":[{"name":"variantId","required":true,"in":"path","description":"Variant ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Variant deleted"},"400":{"description":"Cannot delete the last variant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a variant","tags":["Merchant API - Product Variants"]}},"/merchant/v1/products/{productId}/images/async":{"post":{"description":"Accepts the file with 202 and processes it in the background. Max file size: 10MB. Allowed types: jpeg, png, webp, avif. Poll the status endpoint until READY.","operationId":"MerchantImagesController_uploadImage","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"image":{"type":"string","format":"binary","description":"Image file to upload"},"alt":{"type":"string","description":"Alt text for the image"},"position":{"type":"number","description":"Position in the image list"}},"required":["image"]}}}},"responses":{"202":{"description":"Upload accepted, processing in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncImageUploadResultDto"}}}},"400":{"description":"Invalid file (size, type, or extension)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"402":{"description":"Storage limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Shop or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Upload an image asynchronously","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/async/bulk":{"post":{"description":"Accepts up to 20 files with 202 and a batchId. Poll the batch status endpoint for progress.","operationId":"MerchantImagesController_uploadBulk","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"images":{"type":"array","items":{"type":"string","format":"binary"},"description":"Image files to upload"}},"required":["images"]}}}},"responses":{"202":{"description":"Bulk upload accepted, processing in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImageUploadResultDto"}}}},"400":{"description":"Invalid files or limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"402":{"description":"Storage limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Shop or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Upload multiple images asynchronously","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/async/batch/{batchId}/status":{"get":{"description":"Progress of a bulk upload (total, ready, failed).","operationId":"MerchantImagesController_getBatchStatus","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"batchId","required":true,"in":"path","description":"Batch ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Batch processing status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchStatusResponseDto"}}}},"404":{"description":"Batch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get bulk upload batch status","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/async/{imageId}/status":{"get":{"description":"Current processing status (PENDING, UPLOADING, PROCESSING, READY, FAILED).","operationId":"MerchantImagesController_getImageStatus","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","description":"Image ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Image processing status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageStatusResponseDto"}}}},"404":{"description":"Image not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get image processing status","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/reorder":{"patch":{"description":"Provide image IDs in the desired order.","operationId":"MerchantImagesController_reorderImages","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderImagesDto"}}}},"responses":{"200":{"description":"Images reordered","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductImageDto"}}}}},"400":{"description":"Invalid image IDs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Reorder product images","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/{imageId}/featured":{"patch":{"description":"Marks the image as the featured one for the product.","operationId":"MerchantImagesController_setFeaturedImage","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","description":"Image ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Featured image set"},"400":{"description":"Image does not belong to the product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Image not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Set the featured image","tags":["Merchant API - Product Images"]}},"/merchant/v1/products/{productId}/images/{imageId}":{"delete":{"operationId":"MerchantImagesController_deleteImage","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","description":"Image ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Image deleted"},"404":{"description":"Image not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a product image","tags":["Merchant API - Product Images"]}},"/merchant/v1/attributes":{"get":{"description":"Lists attribute definitions with filtering and pagination. Read scope deliberately spans BOTH families (merchant-filled metadata AND customer configurator fields) so integrations can browse the full catalog of definitions; write operations on this resource are limited to metadata attributes — configurator fields are managed through the configurator resource.","operationId":"MerchantAttributesController_listAttributes","parameters":[{"name":"type","required":false,"in":"query","description":"Filter by attribute type (comma-separated for multi-select)","schema":{"type":"array","items":{"$ref":"#/components/schemas/AttributeType"}}},{"name":"isVisible","required":false,"in":"query","description":"Filter by visible-on-product flag","schema":{"type":"boolean"}},{"name":"isFilterable","required":false,"in":"query","description":"Filter by filterable flag","schema":{"type":"boolean"}},{"name":"isRequired","required":false,"in":"query","description":"Filter by required flag","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search by attribute name or slug","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantAttributeOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantAttributeOrderDir"}}],"responses":{"200":{"description":"Attribute definitions matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAttributeResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List attribute definitions","tags":["Merchant API - Attributes"]},"post":{"description":"Creates a product metadata attribute (e.g. Manufacturer, Material). Customer configurator options are not configurable here.","operationId":"MerchantAttributesController_createAttribute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantCreateAttributeDto"}}}},"responses":{"201":{"description":"Attribute created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create an attribute definition","tags":["Merchant API - Attributes"]}},"/merchant/v1/attributes/{attributeId}":{"get":{"description":"Returns a definition of either family (metadata or configurator field). Writes on this resource accept only metadata attributes (409 otherwise).","operationId":"MerchantAttributesController_getAttribute","parameters":[{"name":"attributeId","required":true,"in":"path","description":"Attribute ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Attribute found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get an attribute definition by ID","tags":["Merchant API - Attributes"]},"patch":{"description":"The attribute type cannot be changed after creation.","operationId":"MerchantAttributesController_updateAttribute","parameters":[{"name":"attributeId","required":true,"in":"path","description":"Attribute ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantUpdateAttributeDto"}}}},"responses":{"200":{"description":"Attribute updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug conflict, or the definition is a customer configurator field (manage it via the configurator resource)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update an attribute definition","tags":["Merchant API - Attributes"]},"delete":{"description":"Removes the attribute definition and its stored values from all products.","operationId":"MerchantAttributesController_deleteAttribute","parameters":[{"name":"attributeId","required":true,"in":"path","description":"Attribute ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Attribute deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAttributeResultDto"}}}},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"The definition is a customer configurator field (manage it via the configurator resource)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete an attribute definition","tags":["Merchant API - Attributes"]}},"/merchant/v1/categories":{"get":{"description":"Lists categories ordered by sort order. Filter by parentId for a single level, or omit it to fetch every category and rebuild the tree from parentId / level / path.","operationId":"MerchantCategoriesController_listCategories","parameters":[{"name":"parentId","required":false,"in":"query","description":"Filter by parent category ID to list only its direct children. Omit to list every category — each item carries parentId, level and path so you can rebuild the tree.","schema":{"format":"uuid","type":"string"}},{"name":"isActive","required":false,"in":"query","description":"Filter by active flag","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Categories matching the filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryResponseDto"}}}}}},"security":[{"api-key":[]}],"summary":"List categories","tags":["Merchant API - Categories"]},"post":{"description":"Creates a category. Set parentId to nest it under another category (omit for a root category).","operationId":"MerchantCategoriesController_createCategory","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryDto"}}}},"responses":{"201":{"description":"Category created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Parent category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a category","tags":["Merchant API - Categories"]}},"/merchant/v1/categories/{categoryId}":{"get":{"operationId":"MerchantCategoriesController_getCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Category ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Category found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponseDto"}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a category by ID","tags":["Merchant API - Categories"]},"patch":{"operationId":"MerchantCategoriesController_updateCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Category ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCategoryDto"}}}},"responses":{"200":{"description":"Category updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponseDto"}}}},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a category","tags":["Merchant API - Categories"]},"delete":{"description":"Deletes a category. Any child categories are re-parented to root (their parentId is cleared).","operationId":"MerchantCategoriesController_deleteCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Category ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Category deleted"},"404":{"description":"Category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a category","tags":["Merchant API - Categories"]}},"/merchant/v1/products/{productId}/attributes":{"get":{"description":"Returns the product specification — the attribute values set on this product (e.g. Brand = \"Hasbro\"). Each entry carries the attribute definition and the stored value.","operationId":"MerchantProductAttributesController_listProductAttributes","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Product attribute values","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductAttributeResponseDto"}}}}}},"security":[{"api-key":[]}],"summary":"List a product's attribute values","tags":["Merchant API - Product Attributes"]}},"/merchant/v1/products/{productId}/attributes/{attributeDefinitionId}":{"put":{"description":"Creates or updates the value of one attribute on the product (every other value is left untouched). Only merchant-filled attributes are accepted — customer configurator fields are rejected.","operationId":"MerchantProductAttributesController_setProductAttribute","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"attributeDefinitionId","required":true,"in":"path","description":"Attribute definition ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantSetProductAttributeValueDto"}}}},"responses":{"200":{"description":"Attribute value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductAttributeResponseDto"}}}},"400":{"description":"Invalid value for the attribute type, or the attribute is customer-filled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Product or attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Set a single attribute value on a product","tags":["Merchant API - Product Attributes"]},"delete":{"description":"Clears the value of one attribute on the product. Idempotent — removing a value that is not set still returns 204.","operationId":"MerchantProductAttributesController_deleteProductAttribute","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"attributeDefinitionId","required":true,"in":"path","description":"Attribute definition ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Attribute value removed"}},"security":[{"api-key":[]}],"summary":"Remove a single attribute value from a product","tags":["Merchant API - Product Attributes"]}},"/merchant/v1/analytics/summary":{"get":{"description":"Cross-module KPIs over [dateFrom, dateTo] (defaults to the last 30 days): sales, order and payment-status breakdowns, cart funnel, customers, fulfillment, catalog health and top products. All monetary values are in the shop currency, minor units.","operationId":"MerchantAnalyticsController_getSummary","parameters":[{"name":"dateFrom","required":false,"in":"query","description":"Start of the window (ISO 8601). Defaults to 30 days before dateTo.","schema":{"format":"date-time","type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"End of the window (ISO 8601). Defaults to now.","schema":{"format":"date-time","type":"string"}},{"name":"compareWith","required":false,"in":"query","description":"Set to \"previous\" to include percentage deltas vs the preceding period of equal length.","schema":{"type":"string","enum":["previous"]}}],"responses":{"200":{"description":"Aggregated analytics for the period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantAnalyticsSummaryDto"}}}},"400":{"description":"Invalid date range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get an aggregated analytics summary","tags":["Merchant API - Analytics"]}},"/merchant/v1/analytics/sales-trend":{"get":{"description":"Daily revenue and order counts over [dateFrom, dateTo] (defaults to the last 30 days). Empty days are returned with zeros so the series is continuous.","operationId":"MerchantAnalyticsController_getSalesTrend","parameters":[{"name":"dateFrom","required":false,"in":"query","description":"Start of the window (ISO 8601). Defaults to 30 days before dateTo.","schema":{"format":"date-time","type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"End of the window (ISO 8601). Defaults to now.","schema":{"format":"date-time","type":"string"}}],"responses":{"200":{"description":"Daily revenue/orders series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MerchantSalesTrendPointDto"}}}}},"400":{"description":"Invalid date range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a daily sales trend","tags":["Merchant API - Analytics"]}},"/merchant/v1/discounts":{"get":{"description":"Lists the shop discount codes with optional filters (lifecycle status, type, code kind, active switch), search, sorting and pagination.","operationId":"MerchantDiscountsController_listDiscounts","parameters":[{"name":"type","required":false,"in":"query","description":"Filter by discount type (comma-separated for multi-select, e.g. PERCENTAGE,FIXED_AMOUNT)","schema":{"type":"array","items":{"$ref":"#/components/schemas/DiscountType"}}},{"name":"isActive","required":false,"in":"query","description":"Filter by the on/off switch alone. To ask what is currently USABLE use `status` instead — a switched-on offer can still be expired or not yet started.","schema":{"type":"boolean"}},{"name":"status","required":false,"in":"query","description":"Filter by lifecycle status (comma-separated for multi-select): the switch AND the schedule combined, same value the response carries. `disabled` wins over the dates.","schema":{"type":"array","items":{"$ref":"#/components/schemas/DiscountLifecycleStatus"}}},{"name":"requiresGrant","required":false,"in":"query","description":"Filter by code kind. Grant-gated offers mint a personal code per recipient — their own `code` is an internal identifier and must NOT be handed to customers, so pass `false` to list codes safe to distribute.","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search by discount code or title","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","description":"Sort axis. Offers with no end date sort last in BOTH directions on `endsAt`.","schema":{"$ref":"#/components/schemas/MerchantDiscountOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/SortDirection"}}],"responses":{"200":{"description":"Discount codes matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountListResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List discount codes","tags":["Merchant API - Discounts"]},"post":{"description":"Supports percentage, fixed-amount, free-shipping and buy-X-get-Y discounts.","operationId":"MerchantDiscountsController_createDiscount","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiscountDto"}}}},"responses":{"201":{"description":"Discount created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Discount code already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a discount code","tags":["Merchant API - Discounts"]}},"/merchant/v1/discounts/code/{code}":{"get":{"operationId":"MerchantDiscountsController_getDiscountByCode","parameters":[{"name":"code","required":true,"in":"path","description":"Discount code (case-insensitive)","schema":{"type":"string"}}],"responses":{"200":{"description":"Discount found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountResponseDto"}}}},"404":{"description":"Discount not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a discount code by its code","tags":["Merchant API - Discounts"]}},"/merchant/v1/discounts/{discountId}":{"get":{"operationId":"MerchantDiscountsController_getDiscount","parameters":[{"name":"discountId","required":true,"in":"path","description":"Discount ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Discount found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountResponseDto"}}}},"404":{"description":"Discount not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a discount code by ID","tags":["Merchant API - Discounts"]},"patch":{"operationId":"MerchantDiscountsController_updateDiscount","parameters":[{"name":"discountId","required":true,"in":"path","description":"Discount ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDiscountDto"}}}},"responses":{"200":{"description":"Discount updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountResponseDto"}}}},"404":{"description":"Discount not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a discount code","tags":["Merchant API - Discounts"]},"delete":{"description":"Permanently deletes the discount code and its usage history.","operationId":"MerchantDiscountsController_deleteDiscount","parameters":[{"name":"discountId","required":true,"in":"path","description":"Discount ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Discount deleted"},"404":{"description":"Discount not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a discount code","tags":["Merchant API - Discounts"]}},"/merchant/v1/blog/categories":{"get":{"description":"Lists every blog category, each with its post count.","operationId":"MerchantBlogController_listCategories","parameters":[],"responses":{"200":{"description":"Blog categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlogCategoryResponseDto"}}}}}},"security":[{"api-key":[]}],"summary":"List blog categories","tags":["Merchant API - Blog"]},"post":{"operationId":"MerchantBlogController_createCategory","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBlogCategoryDto"}}}},"responses":{"201":{"description":"Blog category created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogCategoryResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a blog category","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/categories/{categoryId}":{"get":{"operationId":"MerchantBlogController_getCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Blog category ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Blog category found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogCategoryResponseDto"}}}},"404":{"description":"Blog category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a blog category by ID","tags":["Merchant API - Blog"]},"patch":{"operationId":"MerchantBlogController_updateCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Blog category ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlogCategoryDto"}}}},"responses":{"200":{"description":"Blog category updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogCategoryResponseDto"}}}},"404":{"description":"Blog category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a blog category","tags":["Merchant API - Blog"]},"delete":{"description":"Deletes a blog category. Posts in that category are kept and become uncategorized.","operationId":"MerchantBlogController_deleteCategory","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Blog category ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Blog category deleted"},"404":{"description":"Blog category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a blog category","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/tags":{"get":{"description":"Lists every blog tag, each with its post count.","operationId":"MerchantBlogController_listTags","parameters":[],"responses":{"200":{"description":"Blog tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlogTagResponseDto"}}}}}},"security":[{"api-key":[]}],"summary":"List blog tags","tags":["Merchant API - Blog"]},"post":{"operationId":"MerchantBlogController_createTag","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBlogTagDto"}}}},"responses":{"201":{"description":"Blog tag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogTagResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a blog tag","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/tags/{tagId}":{"patch":{"description":"Renames a blog tag. Posts keep the tag — use this instead of deleting and recreating it.","operationId":"MerchantBlogController_updateTag","parameters":[{"name":"tagId","required":true,"in":"path","description":"Blog tag ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlogTagDto"}}}},"responses":{"200":{"description":"Blog tag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogTagResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Blog tag not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a blog tag","tags":["Merchant API - Blog"]},"delete":{"description":"Deletes a blog tag and detaches it from every post.","operationId":"MerchantBlogController_deleteTag","parameters":[{"name":"tagId","required":true,"in":"path","description":"Blog tag ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Blog tag deleted"},"404":{"description":"Blog tag not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a blog tag","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts":{"get":{"description":"Lists blog posts (newest first) with offset pagination. Filter by status and/or category.","operationId":"MerchantBlogController_listPosts","parameters":[{"name":"status","required":false,"in":"query","description":"Filter by post status. Omit to list posts in every status (draft, published, scheduled, archived).","schema":{"$ref":"#/components/schemas/BlogPostStatus"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by blog category ID.","schema":{"format":"uuid","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"maximum":10000,"default":0,"type":"number"}}],"responses":{"200":{"description":"Paginated blog posts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostsListResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List blog posts","tags":["Merchant API - Blog"]},"post":{"description":"Creates a blog post. HTML content is sanitized before it is stored. Set authorName to control the byline shown on the storefront; the API key is recorded as the author of record.","operationId":"MerchantBlogController_createPost","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBlogPostDto"}}}},"responses":{"201":{"description":"Blog post created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a blog post","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts/{postId}":{"get":{"operationId":"MerchantBlogController_getPost","parameters":[{"name":"postId","required":true,"in":"path","description":"Blog post ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Blog post found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostResponseDto"}}}},"404":{"description":"Blog post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a blog post by ID","tags":["Merchant API - Blog"]},"patch":{"description":"Updates a blog post. Only the supplied fields change. HTML content is sanitized before it is stored.","operationId":"MerchantBlogController_updatePost","parameters":[{"name":"postId","required":true,"in":"path","description":"Blog post ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlogPostDto"}}}},"responses":{"200":{"description":"Blog post updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostResponseDto"}}}},"404":{"description":"Blog post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a blog post","tags":["Merchant API - Blog"]},"delete":{"operationId":"MerchantBlogController_deletePost","parameters":[{"name":"postId","required":true,"in":"path","description":"Blog post ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Blog post deleted"},"404":{"description":"Blog post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a blog post","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts/{postId}/product-selection":{"get":{"description":"Returns the stored selection (direct product IDs, product category IDs, collection IDs). The storefront shows the union of the three lists. Empty arrays when nothing is pinned.","operationId":"MerchantBlogController_getPostProductSelection","parameters":[{"name":"postId","required":true,"in":"path","description":"Blog post ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Stored product selection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"404":{"description":"Blog post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get the product selection pinned to a blog post","tags":["Merchant API - Blog"]},"put":{"description":"Replaces the whole selection with the supplied lists (direct product IDs, product category IDs, collection IDs). Send three empty arrays to remove the selection. Every referenced product, category and collection must exist.","operationId":"MerchantBlogController_setPostProductSelection","parameters":[{"name":"postId","required":true,"in":"path","description":"Blog post ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionInputDto"}}}},"responses":{"200":{"description":"Stored product selection after the write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Blog post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Replace the product selection pinned to a blog post","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/categories/{categoryId}/product-selection":{"get":{"description":"Returns the stored selection (direct product IDs, product category IDs, collection IDs). The storefront shows the union of the three lists. Empty arrays when nothing is pinned.","operationId":"MerchantBlogController_getCategoryProductSelection","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Blog category ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Stored product selection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"404":{"description":"Blog category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get the product selection pinned to a blog category","tags":["Merchant API - Blog"]},"put":{"description":"Replaces the whole selection with the supplied lists (direct product IDs, product category IDs, collection IDs). Send three empty arrays to remove the selection. Every referenced product, category and collection must exist.","operationId":"MerchantBlogController_setCategoryProductSelection","parameters":[{"name":"categoryId","required":true,"in":"path","description":"Blog category ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionInputDto"}}}},"responses":{"200":{"description":"Stored product selection after the write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Blog category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Replace the product selection pinned to a blog category","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/tags/{tagId}/product-selection":{"get":{"description":"Returns the stored selection (direct product IDs, product category IDs, collection IDs). The storefront shows the union of the three lists. Empty arrays when nothing is pinned.","operationId":"MerchantBlogController_getTagProductSelection","parameters":[{"name":"tagId","required":true,"in":"path","description":"Blog tag ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Stored product selection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"404":{"description":"Blog tag not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get the product selection pinned to a blog tag","tags":["Merchant API - Blog"]},"put":{"description":"Replaces the whole selection with the supplied lists (direct product IDs, product category IDs, collection IDs). Send three empty arrays to remove the selection. Every referenced product, category and collection must exist.","operationId":"MerchantBlogController_setTagProductSelection","parameters":[{"name":"tagId","required":true,"in":"path","description":"Blog tag ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionInputDto"}}}},"responses":{"200":{"description":"Stored product selection after the write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductSelectionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Blog tag not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Replace the product selection pinned to a blog tag","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts/bulk-delete":{"post":{"description":"Deletes up to 500 posts in one call. Reports a per-id result — missing ids come back as NOT_FOUND.","operationId":"MerchantBlogController_bulkDeletePosts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsDto"}}}},"responses":{"200":{"description":"Per-id bulk result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkActionResultDto"}}}}},"security":[{"api-key":[]}],"summary":"Bulk delete blog posts","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts/bulk-publish":{"post":{"description":"Publishes up to 500 posts in one call (sets each publish date if not already set). Reports a per-id result — missing ids come back as NOT_FOUND.","operationId":"MerchantBlogController_bulkPublishPosts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsDto"}}}},"responses":{"200":{"description":"Per-id bulk result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkActionResultDto"}}}}},"security":[{"api-key":[]}],"summary":"Bulk publish blog posts","tags":["Merchant API - Blog"]}},"/merchant/v1/blog/posts/bulk-unpublish":{"post":{"description":"Reverts up to 500 posts to draft in one call (publish date is kept for a later republish). Reports a per-id result — missing ids come back as NOT_FOUND.","operationId":"MerchantBlogController_bulkUnpublishPosts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsDto"}}}},"responses":{"200":{"description":"Per-id bulk result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkActionResultDto"}}}}},"security":[{"api-key":[]}],"summary":"Bulk unpublish blog posts","tags":["Merchant API - Blog"]}},"/merchant/v1/configurator/fields":{"get":{"description":"Lists global configurator field definitions (fields the customer answers at purchase). Per-product fields live under /merchant/v1/products/{productId}/configurator/fields.","operationId":"MerchantConfiguratorController_listFields","parameters":[{"name":"type","required":false,"in":"query","description":"Filter by attribute type (comma-separated for multi-select)","schema":{"type":"array","items":{"$ref":"#/components/schemas/AttributeType"}}},{"name":"isVisible","required":false,"in":"query","description":"Filter by visible-on-product flag","schema":{"type":"boolean"}},{"name":"isFilterable","required":false,"in":"query","description":"Filter by filterable flag","schema":{"type":"boolean"}},{"name":"isRequired","required":false,"in":"query","description":"Filter by required flag","schema":{"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search by attribute name or slug","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"orderBy","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantAttributeOrderBy"}},{"name":"orderDir","required":false,"in":"query","schema":{"$ref":"#/components/schemas/MerchantAttributeOrderDir"}}],"responses":{"200":{"description":"Configurator fields matching the filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAttributeResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List configurator fields","tags":["Merchant API - Configurator"]},"post":{"description":"Creates a global field the customer answers at purchase — a choice with surcharges, a stock-linked component selector or a free-form input. Use `showIfConditions` to model a sub-component that only appears when a specific parent option is selected. Defaults to fillingMode CUSTOMER.","operationId":"MerchantConfiguratorController_createField","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantCreateConfiguratorFieldDto"}}}},"responses":{"201":{"description":"Configurator field created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a configurator field","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/fields/{fieldId}":{"get":{"operationId":"MerchantConfiguratorController_getField","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field (attribute definition) ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Configurator field found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"404":{"description":"Field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"The definition is a metadata attribute, not a configurator field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get a configurator field by ID","tags":["Merchant API - Configurator"]},"patch":{"description":"The field type cannot be changed after creation. When `options` is provided it REPLACES the whole option list — options omitted from the payload are DELETED together with their per-product overrides; include existing option `id`s to keep them. `showIfConditions`: empty array clears (field always visible), omit to preserve. Deleting an option that other fields reference in their `showIfConditions` hides those sub-components (fail-closed).","operationId":"MerchantConfiguratorController_updateField","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantUpdateConfiguratorFieldDto"}}}},"responses":{"200":{"description":"Configurator field updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}}}},"404":{"description":"Field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug conflict or metadata attribute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a configurator field","tags":["Merchant API - Configurator"]},"delete":{"description":"Removes the field definition with its options, per-product overrides and stored values. Other fields whose `showIfConditions` reference this field become hidden (fail-closed).","operationId":"MerchantConfiguratorController_deleteField","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Configurator field deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAttributeResultDto"}}}},"404":{"description":"Field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"The definition is a metadata attribute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a configurator field","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/fields/{fieldId}/options":{"post":{"description":"Adds a single option without touching the others (safe for concurrent integrations — no replace-all). A linked stock variant and a manual surcharge are mutually exclusive: setting `linkedVariantId` clears the surcharge (the component is priced from the variant).","operationId":"MerchantConfiguratorController_addOption","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAttributeOptionDto"}}}},"responses":{"201":{"description":"Option created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeOptionDetailResponseDto"}}}},"400":{"description":"Invalid input (field type has no options, field is not customer-fillable…)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Field or linked variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Option value already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Add an option to a configurator field","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/fields/{fieldId}/options/{optionId}":{"patch":{"description":"Partial update — omitted properties are preserved, null clears nullable properties.","operationId":"MerchantConfiguratorController_updateOption","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field ID","schema":{"type":"string"}},{"name":"optionId","required":true,"in":"path","description":"Option ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAttributeOptionDto"}}}},"responses":{"200":{"description":"Option updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeOptionDetailResponseDto"}}}},"404":{"description":"Option not found under this field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update a configurator field option","tags":["Merchant API - Configurator"]},"delete":{"description":"Deletes the option together with its per-product overrides. Fields whose `showIfConditions` reference this option become hidden (fail-closed) — review sub-component conditions after deleting.","operationId":"MerchantConfiguratorController_deleteOption","parameters":[{"name":"fieldId","required":true,"in":"path","description":"Configurator field ID","schema":{"type":"string"}},{"name":"optionId","required":true,"in":"path","description":"Option ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Option deleted"},"404":{"description":"Option not found under this field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a configurator field option","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/sets":{"get":{"description":"Attribute sets are named templates of fields shared by many products (e.g. \"Copier configurator\").","operationId":"MerchantConfiguratorController_listSets","parameters":[],"responses":{"200":{"description":"All attribute sets of the shop","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttributeSetResponseDto"}}}}}},"security":[{"api-key":[]}],"summary":"List attribute sets","tags":["Merchant API - Configurator"]},"post":{"description":"The order of `attributeIds` defines the field order customers see on the product page. Only global attribute definitions can be included (per-product fields cannot join a shared set). Assign the set to a product via POST/PATCH /merchant/v1/products (`attributeSetId`).","operationId":"MerchantConfiguratorController_createSet","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAttributeSetDto"}}}},"responses":{"201":{"description":"Attribute set created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeSetResponseDto"}}}},"400":{"description":"Invalid input (e.g. a per-product field in attributeIds)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create an attribute set","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/sets/{setId}":{"get":{"operationId":"MerchantConfiguratorController_getSet","parameters":[{"name":"setId","required":true,"in":"path","description":"Attribute set ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Attribute set found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeSetResponseDto"}}}},"404":{"description":"Attribute set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get an attribute set by ID","tags":["Merchant API - Configurator"]},"patch":{"description":"When `attributeIds` is provided it REPLACES the set contents and order — fields omitted from the list leave the set (products keep their per-product fields and overrides).","operationId":"MerchantConfiguratorController_updateSet","parameters":[{"name":"setId","required":true,"in":"path","description":"Attribute set ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAttributeSetDto"}}}},"responses":{"200":{"description":"Attribute set updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeSetResponseDto"}}}},"404":{"description":"Attribute set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Update an attribute set","tags":["Merchant API - Configurator"]},"delete":{"description":"Products using the set lose the template binding (their attributeSetId becomes null); the field definitions themselves are NOT deleted.","operationId":"MerchantConfiguratorController_deleteSet","parameters":[{"name":"setId","required":true,"in":"path","description":"Attribute set ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Attribute set deleted"},"404":{"description":"Attribute set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete an attribute set","tags":["Merchant API - Configurator"]}},"/merchant/v1/configurator/products":{"get":{"description":"Products that have at least one per-product field or an assigned attribute set. Lets an integration find configurator-enabled products without querying every product individually.","operationId":"MerchantConfiguratorController_listProducts","parameters":[{"name":"search","required":false,"in":"query","description":"Search by product name or slug.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Items to skip","schema":{"minimum":0,"maximum":10000,"default":0,"type":"number"}}],"responses":{"200":{"description":"Products with a configurator","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductWithConfiguratorDto"}}}}}},"security":[{"api-key":[]}],"summary":"List products with a configurator","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator":{"get":{"description":"The composed configurator exactly as the storefront resolves it: attribute-set fields plus per-product fields, with per-product option overrides applied, hidden options/fields removed and visibility conditions attached. A product without a configurator returns an empty list; an unknown product is 404.","operationId":"MerchantProductConfiguratorController_getEffectiveConfigurator","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Effective configurator fields","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductConfiguratorFieldAdminDto"}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Get the effective product configurator","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/fields":{"get":{"description":"Fields defined only for this product (not part of any shared attribute set).","operationId":"MerchantProductConfiguratorController_listFields","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-product fields","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScopedAttributeDefinitionResponseDto"}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List per-product configurator fields","tags":["Merchant API - Configurator"]},"post":{"description":"Creates a field visible only on this product (e.g. an accessory available for one model). Use `showIfConditions` referencing a parent field option to model a sub-component that only appears when that option is selected. Defaults to fillingMode CUSTOMER.","operationId":"MerchantProductConfiguratorController_createField","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantCreateConfiguratorFieldDto"}}}},"responses":{"201":{"description":"Field created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopedAttributeDefinitionResponseDto"}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists on this product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Create a per-product configurator field","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/fields/{fieldId}":{"delete":{"description":"Removes the field with its options and stored values. Only fields of THIS product can be deleted here.","operationId":"MerchantProductConfiguratorController_deleteField","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"fieldId","required":true,"in":"path","description":"Per-product field ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Field deleted"},"404":{"description":"Field not found on this product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Delete a per-product configurator field","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/fields/from/{sourceFieldId}":{"post":{"description":"Copies a global configurator field (typically one detached from a set) as a field scoped to this product. Linked stock variants are cleared on the copy (link them per product afterwards); visibility conditions are cleared (the parent context differs between products).","operationId":"MerchantProductConfiguratorController_copyFieldAsScoped","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"sourceFieldId","required":true,"in":"path","description":"Global configurator field ID to copy","schema":{"type":"string"}}],"responses":{"201":{"description":"Field copied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopedAttributeDefinitionResponseDto"}}}},"400":{"description":"Source is a merchant-filled metadata attribute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"409":{"description":"Slug already exists on this product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Copy an existing field as a per-product field","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/option-overrides":{"get":{"description":"Per-product customizations of global field options. An option without an override inherits the global surcharge / linked variant.","operationId":"MerchantProductConfiguratorController_listOverrides","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Overrides of this product","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductAttributeOptionOverrideResponseDto"}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List option overrides for this product","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/option-overrides/{optionId}":{"put":{"description":"Customizes one global option for this product: a different surcharge, a different linked stock variant or hiding the option. `linkedVariantExplicit=true` makes `linkedVariantId` literal (including null = \"explicitly detached\"); false inherits the global link. A linked variant and a manual surcharge are mutually exclusive — setting the variant clears the surcharge. Calling PUT again replaces the override.","operationId":"MerchantProductConfiguratorController_upsertOverride","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"optionId","required":true,"in":"path","description":"Global option ID being overridden","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertProductAttributeOverrideDto"}}}},"responses":{"200":{"description":"Override stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductAttributeOptionOverrideResponseDto"}}}},"400":{"description":"Option belongs to a field customers cannot fill","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Product, option or linked variant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Set an option override for this product","tags":["Merchant API - Configurator"]},"delete":{"description":"The option reverts to inheriting the global surcharge / linked variant.","operationId":"MerchantProductConfiguratorController_deleteOverride","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"optionId","required":true,"in":"path","description":"Global option ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Override removed (idempotent)"}},"security":[{"api-key":[]}],"summary":"Remove an option override","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/disabled-fields":{"get":{"description":"Attribute-set fields the merchant hid for this specific product.","operationId":"MerchantProductConfiguratorController_listDisabledFields","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Hidden fields","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductDisabledAttributeResponseDto"}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"List fields hidden on this product","tags":["Merchant API - Configurator"]},"post":{"description":"Hides a whole attribute-set field for this product (the customer will not see it). Idempotent — hiding an already-hidden field succeeds.","operationId":"MerchantProductConfiguratorController_disableField","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerchantDisableConfiguratorFieldDto"}}}},"responses":{"201":{"description":"Field hidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDisabledAttributeResponseDto"}}}},"404":{"description":"Product or field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Hide a field on this product","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/disabled-fields/{fieldId}":{"delete":{"operationId":"MerchantProductConfiguratorController_enableField","parameters":[{"name":"productId","required":true,"in":"path","description":"Product ID","schema":{"type":"string"}},{"name":"fieldId","required":true,"in":"path","description":"Field (attribute definition) ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Field visible again"},"404":{"description":"Field was not hidden on this product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Show a hidden field again on this product","tags":["Merchant API - Configurator"]}},"/merchant/v1/products/{productId}/configurator/copy-from/{sourceProductId}":{"post":{"description":"Copies the attribute-set binding (when this product has none), all per-product fields with their options and visibility conditions (references rewritten to the copies), option overrides and hidden fields from the source product. Idempotent — fields whose slug already exists here are skipped, so retrying after a timeout is safe. Rejects when the source configurator references component variants that have since been withdrawn.","operationId":"MerchantProductConfiguratorController_copyFromProduct","parameters":[{"name":"productId","required":true,"in":"path","description":"Target product ID","schema":{"type":"string"}},{"name":"sourceProductId","required":true,"in":"path","description":"Source (template) product ID","schema":{"type":"string"}}],"responses":{"201":{"description":"Configurator copied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateConfiguratorResultDto"}}}},"400":{"description":"Source references a non-sellable component variant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Source or target product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Copy the configurator from another product","tags":["Merchant API - Configurator"]}}},"info":{"title":"DoSwiftly Merchant API","description":"External REST API for merchant integrations — ERP connectors, warehouse synchronization, order export and custom tooling.\n\n## Authentication\nCreate an API key in the admin panel (Settings → API keys) and send it with every request in the `Authorization: Bearer sk_live_...` header. Each key carries per-resource read/write permissions; a missing permission yields `403`.\n\n## Rate limiting\nRequests are limited per key (default 5000/min, configurable per key). Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers; exceeding the limit yields `429` with a `Retry-After` header.\n\n## Localization\nError messages are localized via the `Accept-Language` header (`pl` default, `en` supported).","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"api-key":{"scheme":"bearer","bearerFormat":"API key","type":"http","description":"API key created in the admin panel (Settings → API keys), sent as `Authorization: Bearer sk_live_...`."}},"schemas":{"ProductStatus":{"type":"string","enum":["DRAFT","ACTIVE","ARCHIVED"]},"MerchantProductOrderBy":{"type":"string","enum":["name","price","createdAt","updatedAt"]},"SortDirection":{"type":"string","enum":["asc","desc"]},"ProductType":{"type":"string","enum":["PHYSICAL","DIGITAL","SERVICE","SUBSCRIPTION","GIFT_CARD"],"description":"Product type"},"StockAvailability":{"type":"string","enum":["UNTRACKED","IN_STOCK","BACKORDER","OUT_OF_STOCK"],"description":"Read model: stock availability state. UNTRACKED = inventory is not tracked for this product, IN_STOCK = units available, BACKORDER = sellable while depleted, OUT_OF_STOCK = nothing to sell."},"ProductResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Product ID"},"name":{"type":"string","description":"Product name"},"slug":{"type":"string","description":"URL-friendly slug"},"description":{"type":"string","description":"Product description"},"shortDescription":{"type":"string","description":"Short description"},"type":{"description":"Product type","allOf":[{"$ref":"#/components/schemas/ProductType"}]},"status":{"description":"Product status","allOf":[{"$ref":"#/components/schemas/ProductStatus"}]},"brandId":{"type":"string","description":"Brand ID"},"price":{"type":"number","description":"Price in cents"},"compareAtPrice":{"type":"number","description":"Compare at price in cents"},"costPrice":{"type":"number","description":"Cost price in cents"},"currency":{"type":"string","description":"Currency code"},"weight":{"type":"number","description":"Weight in grams"},"dimensions":{"type":"object","description":"Product dimensions","additionalProperties":true},"requiresShipping":{"type":"boolean","description":"Requires shipping"},"trackQuantity":{"type":"boolean","description":"Track inventory quantity. null = inherit from shop settings","nullable":true},"quantity":{"type":"number","description":"Quantity in stock"},"allowBackorder":{"type":"boolean","description":"Allow backorders. null = inherit from shop settings","nullable":true},"hasAvailableStock":{"type":"boolean","description":"Read model: whether any variant is sellable — honours the full variant ?? product ?? shop tracking chain plus backorder."},"isInventoryTracked":{"type":"boolean","description":"Read model: effective product-level inventory tracking (product ?? shop settings)."},"availability":{"description":"Read model: stock availability state. UNTRACKED = inventory is not tracked for this product, IN_STOCK = units available, BACKORDER = sellable while depleted, OUT_OF_STOCK = nothing to sell.","allOf":[{"$ref":"#/components/schemas/StockAvailability"}]},"taxCode":{"type":"string","description":"Tax code"},"quantityMin":{"type":"number","description":"Minimum purchase quantity"},"quantityIncrement":{"type":"number","description":"Quantity must be purchased in multiples of this value"},"tags":{"description":"Product tags","type":"array","items":{"type":"string"}},"attributes":{"type":"array","description":"Product attributes (key-value pairs)","items":{"type":"object"}},"images":{"type":"array","description":"Product images","items":{"type":"string"}},"featuredImage":{"type":"string","description":"Featured image URL"},"featuredImageId":{"type":"string","description":"Featured image ID","nullable":true},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"},"translations":{"type":"object","description":"Translations by locale","additionalProperties":true},"isActive":{"type":"boolean","description":"Derived publish flag: true when `status` is ACTIVE."},"publishedAt":{"type":"string","description":"Published at timestamp","format":"date-time"},"viewCount":{"type":"number","description":"View count"},"salesCount":{"type":"number","description":"Sales count"},"averageRating":{"type":"number","description":"Average rating"},"reviewCount":{"type":"number","description":"Review count"},"createdBy":{"type":"string","description":"Created by user ID"},"updatedBy":{"type":"string","description":"Updated by user ID"},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"},"deletedAt":{"type":"string","description":"Deleted at timestamp (soft delete)","format":"date-time"}},"required":["id","name","slug","type","status","price","currency","requiresShipping","trackQuantity","quantity","allowBackorder","tags","isActive","viewCount","salesCount","reviewCount","createdAt","updatedAt"]},"ProductListResponseDto":{"type":"object","properties":{"products":{"description":"Products matching the query filters.","type":"array","items":{"$ref":"#/components/schemas/ProductResponseDto"}},"total":{"type":"number","description":"Total number of products matching the filters (before pagination).","example":42}},"required":["products","total"]},"ErrorResponseDto":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code","example":400},"message":{"description":"Error message(s)","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"example":"Validation failed"},"error":{"type":"string","description":"Error type","example":"Bad Request"},"timestamp":{"type":"string","description":"ISO 8601 timestamp","example":"2024-12-15T10:30:00.000Z"},"path":{"type":"string","description":"Request path","example":"/v1/commerce/shops/123/products"}},"required":["statusCode","message","error"]},"DimensionsDto":{"type":"object","properties":{"length":{"type":"number","description":"Length"},"width":{"type":"number","description":"Width"},"height":{"type":"number","description":"Height"},"unit":{"type":"string","description":"Unit of measurement","enum":["cm","in","mm","m"],"default":"cm"}}},"ProductVisibility":{"type":"string","enum":["PUBLIC","HIDDEN","BUNDLE_ONLY"]},"CreateProductDto":{"type":"object","properties":{"name":{"type":"string","description":"Product name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Product description (sanitized HTML, max 50k chars)","maxLength":50000},"shortDescription":{"type":"string","description":"Short description","maxLength":500},"type":{"default":"PHYSICAL","allOf":[{"$ref":"#/components/schemas/ProductType"}]},"status":{"default":"DRAFT","description":"Merchant-facing lifecycle status. Visibility is derived automatically on backend: ACTIVE->PUBLIC, DRAFT/ARCHIVED->HIDDEN.","allOf":[{"$ref":"#/components/schemas/ProductStatus"}]},"price":{"type":"number","description":"Price in cents","minimum":0},"sku":{"type":"string","description":"Stock Keeping Unit","maxLength":100},"barcode":{"type":"string","description":"Barcode (EAN/UPC)","maxLength":100},"compareAtPrice":{"type":"number","description":"Compare at price in cents"},"costPrice":{"type":"number","description":"Cost price in cents"},"currency":{"type":"string","description":"Currency code. Omitted = the shop sales currency."},"weight":{"type":"number","description":"Weight in grams"},"dimensions":{"description":"Product dimensions","allOf":[{"$ref":"#/components/schemas/DimensionsDto"}]},"requiresShipping":{"type":"boolean","description":"Requires shipping","default":true},"trackQuantity":{"type":"boolean","description":"Track inventory quantity. null = inherit from shop settings","nullable":true},"quantity":{"type":"number","description":"Initial quantity (auto-synced from variants.available after creation)","default":0},"allowBackorder":{"type":"boolean","description":"Allow backorders. null = inherit from shop settings","nullable":true},"taxCode":{"type":"string","description":"Tax code (e.g. VAT code)"},"quantityMin":{"type":"number","description":"Minimum purchase quantity. null clears the rule","nullable":true},"quantityIncrement":{"type":"number","description":"Quantity must be purchased in multiples of this value. null clears the rule","nullable":true},"tags":{"description":"Product tags","type":"array","items":{"type":"string"}},"brandId":{"type":"string","description":"Brand ID. null unassigns the brand","nullable":true,"format":"uuid"},"metaTitle":{"type":"string","description":"SEO meta title","maxLength":255},"metaDescription":{"type":"string","description":"SEO meta description","maxLength":500},"translations":{"type":"object","description":"Translations by locale (key = locale code, e.g. \"pl\")","additionalProperties":true},"categoryIds":{"description":"Category IDs to assign to product","type":"array","items":{"type":"string"}},"attributes":{"type":"array","description":"Product attributes (key-value pairs)"},"visibility":{"default":"PUBLIC","allOf":[{"$ref":"#/components/schemas/ProductVisibility"}]},"attributeSetId":{"type":"string","description":"Shared AttributeSet template ID (nullable)","nullable":true,"format":"uuid"}},"required":["name","slug","price"]},"UpdateProductDto":{"type":"object","properties":{"name":{"type":"string","description":"Product name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Product description (sanitized HTML, max 50k chars)","maxLength":50000},"shortDescription":{"type":"string","description":"Short description","maxLength":500},"status":{"allOf":[{"$ref":"#/components/schemas/ProductStatus"}]},"price":{"type":"number","description":"Price in cents"},"compareAtPrice":{"type":"number","description":"Compare at price in cents"},"costPrice":{"type":"number","description":"Cost price in cents"},"currency":{"type":"string","description":"Currency code"},"weight":{"type":"number","description":"Weight in grams"},"dimensions":{"description":"Product dimensions","allOf":[{"$ref":"#/components/schemas/DimensionsDto"}]},"requiresShipping":{"type":"boolean","description":"Requires shipping"},"trackQuantity":{"type":"boolean","description":"Track inventory for this product. Applies to variants that do not set their own value. Send `null` to inherit the shop-wide setting.","nullable":true},"quantity":{"type":"number","description":"Quantity (read-only, auto-computed from variants.available)"},"allowBackorder":{"type":"boolean","description":"Allow orders when out of stock, for variants that do not set their own value. Send `null` to inherit the shop-wide setting.","nullable":true},"taxCode":{"type":"string","description":"Tax code (e.g. VAT code)"},"quantityMin":{"type":"number","description":"Minimum purchase quantity. null clears the rule","nullable":true},"quantityIncrement":{"type":"number","description":"Quantity must be purchased in multiples of this value. null clears the rule","nullable":true},"tags":{"description":"Product tags","type":"array","items":{"type":"string"}},"brandId":{"type":"string","description":"Brand ID. null unassigns the brand","nullable":true,"format":"uuid"},"metaTitle":{"type":"string","description":"SEO meta title","maxLength":255},"metaDescription":{"type":"string","description":"SEO meta description","maxLength":500},"translations":{"type":"object","description":"Translations by locale (key = locale code, e.g. \"pl\")","additionalProperties":true},"isActive":{"type":"boolean","description":"Derived publish flag — a view of `status`. Setting it without `status` publishes (true → status ACTIVE) or unpublishes (false → status DRAFT). On ARCHIVED products the flag is a no-op in both directions — un-archiving requires an explicit `status`. When `status` is also provided, `status` wins."},"categoryIds":{"description":"Category IDs to assign to product","type":"array","items":{"type":"string"}},"attributes":{"type":"array","description":"Product attributes (key-value pairs)"},"visibility":{"allOf":[{"$ref":"#/components/schemas/ProductVisibility"}]},"attributeSetId":{"type":"string","description":"Shared AttributeSet template ID (null clears binding)","nullable":true,"format":"uuid"}}},"OrderStatus":{"type":"string","enum":["DRAFT","PENDING","CONFIRMED","PROCESSING","ON_HOLD","COMPLETED","CANCELLED","EXPIRED"]},"PaymentStatus":{"type":"string","enum":["UNPAID","PENDING","AUTHORIZED","PAID","PARTIALLY_PAID","PARTIALLY_REFUNDED","REFUNDED","FAILED","CHARGEBACK","VOIDED","REFUND_PENDING"]},"FulfillmentStatus":{"type":"string","enum":["UNFULFILLED","PARTIALLY_FULFILLED","FULFILLED","IN_TRANSIT","DELIVERED","PARTIALLY_RETURNED","RETURNED","LOST"]},"OrderDiscountAllocationDto":{"type":"object","properties":{"discountCode":{"type":"string","description":"Discount code that produced this allocation"},"amount":{"type":"number","description":"Amount discounted by this code in cents"}},"required":["discountCode","amount"]},"OrderItemResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Order item ID"},"productId":{"type":"string","description":"Product ID"},"variantId":{"type":"string","description":"Product variant ID"},"productName":{"type":"string","description":"Product name at time of order"},"variantName":{"type":"string","description":"Variant name at time of order"},"sku":{"type":"string","description":"SKU"},"quantity":{"type":"number","description":"Quantity"},"unitPrice":{"type":"number","description":"Unit price in cents"},"totalPrice":{"type":"number","description":"Total price in cents"},"imageUrl":{"type":"string","description":"Live imgproxy thumbnail URL (admin order detail; absent → frontend placeholder)"},"discountAmount":{"type":"number","description":"Discount amount allocated to this line in cents (sum of discountAllocations)"},"discountAllocations":{"description":"Per-code discount allocations for this line (one entry per code that reduced it; sum equals discountAmount). Absent when no code touches the line or the order predates per-line snapshots.","type":"array","items":{"$ref":"#/components/schemas/OrderDiscountAllocationDto"}},"parentOrderItemId":{"type":"string","description":"Parent order item ID (null for top-level items)","format":"uuid","nullable":true},"baseUnitPrice":{"type":"number","description":"Base unit price in cents (before BUNDLED surcharge roll-in)"},"surchargeAmount":{"type":"number","description":"Surcharge amount in cents (rolled into unitPrice)"},"taxAmount":{"type":"number","description":"Tax amount in cents (frozen at checkout)"},"attributesSnapshot":{"type":"array","description":"Frozen attribute selections snapshot (D-I/D-N audit trail)","items":{"type":"object","additionalProperties":true}}},"required":["id","productId","variantId","productName","variantName","sku","quantity","unitPrice","totalPrice"]},"CountryCode":{"type":"string","enum":["AD","AE","AF","AG","AI","AL","AM","AO","AQ","AR","AS","AT","AU","AW","AX","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BL","BM","BN","BO","BQ","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CW","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","GA","GB","GD","GE","GF","GG","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IM","IN","IO","IQ","IR","IS","IT","JE","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MF","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RS","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","SS","ST","SV","SX","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TL","TM","TN","TO","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","XK","YE","YT","ZA","ZM","ZW","ZZ"],"description":"Country code (ISO 3166-1 alpha-2)"},"PickupPointDto":{"type":"object","properties":{"provider":{"type":"string","description":"Provider code (e.g., inpost, orlen, dpd)"},"pointId":{"type":"string","description":"Point ID (e.g., KRA010, ORLEN_WAW_001)"},"pointName":{"type":"string","description":"Point display name"},"pointAddress":{"type":"string","description":"Point full address"},"locationDescription":{"type":"string","description":"Location description (e.g., \"Near the main entrance\")"}},"required":["provider","pointId"]},"AddressDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name"},"lastName":{"type":"string","description":"Last name"},"company":{"type":"string","description":"Company name"},"address1":{"type":"string","description":"Address line 1"},"address2":{"type":"string","description":"Address line 2"},"buildingNumber":{"type":"string","description":"Building / house number — structured overlay over address1 (required for PL delivery / billing)."},"flatNumber":{"type":"string","description":"Flat / apartment number — optional companion to buildingNumber."},"city":{"type":"string","description":"City"},"province":{"type":"string","description":"State/Province"},"postalCode":{"type":"string","description":"Postal code"},"country":{"description":"Country code (ISO 3166-1 alpha-2)","example":"PL","allOf":[{"$ref":"#/components/schemas/CountryCode"}]},"phone":{"type":"string","description":"Phone number"},"pickupPoint":{"description":"Pickup point for locker/POP deliveries","allOf":[{"$ref":"#/components/schemas/PickupPointDto"}]}},"required":["firstName","lastName","address1","city","postalCode","country"]},"OrderResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Order ID"},"orderNumber":{"type":"string","description":"Order number (human-readable)"},"customerId":{"type":"string","description":"Customer ID"},"email":{"type":"string","description":"Customer email"},"customerInfo":{"type":"object","description":"Customer info snapshot","additionalProperties":true},"status":{"allOf":[{"$ref":"#/components/schemas/OrderStatus"}]},"paymentStatus":{"allOf":[{"$ref":"#/components/schemas/PaymentStatus"}]},"fulfillmentStatus":{"allOf":[{"$ref":"#/components/schemas/FulfillmentStatus"}]},"items":{"description":"Order items","type":"array","items":{"$ref":"#/components/schemas/OrderItemResponseDto"}},"subtotal":{"type":"number","description":"Subtotal in cents"},"shippingCost":{"type":"number","description":"Shipping cost in cents"},"tax":{"type":"number","description":"Tax amount in cents"},"discountAmount":{"type":"number","description":"Discount amount in cents"},"discountAllocations":{"description":"Per-code discount allocations (applicable codes only; sum equals discountAmount)","type":"array","items":{"$ref":"#/components/schemas/OrderDiscountAllocationDto"}},"hasFreeShipping":{"type":"boolean","description":"Whether free shipping discount was applied"},"total":{"type":"number","description":"Total amount in cents"},"currency":{"type":"string","description":"Currency code"},"shippingAddress":{"description":"Shipping address","allOf":[{"$ref":"#/components/schemas/AddressDto"}]},"billingAddress":{"description":"Billing address","allOf":[{"$ref":"#/components/schemas/AddressDto"}]},"shippingMethod":{"type":"string","description":"Shipping method name"},"shippingMethodId":{"type":"string","description":"Shipping method ID for provider lookup"},"paymentProvider":{"type":"string","description":"Payment provider code (PAYU/PRZELEWY24/CASH_ON_DELIVERY)"},"notes":{"type":"string","description":"Order notes"},"customerNote":{"type":"string","description":"Buyer checkout note (customer-provided, distinct from merchant notes)"},"customerLanguage":{"type":"string","description":"Customer language preference"},"paidAt":{"type":"string","description":"When payment was received","format":"date-time"},"shippedAt":{"type":"string","description":"When order was shipped","format":"date-time"},"deliveredAt":{"type":"string","description":"When order was delivered","format":"date-time"},"version":{"type":"number","description":"Optimistic-lock counter (ADR 0042). Pass back as expectedVersion when editing order items; a mismatch means the order changed in the meantime (payment webhook, shipment, another edit)."},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","orderNumber","email","status","paymentStatus","fulfillmentStatus","items","subtotal","shippingCost","tax","discountAmount","discountAllocations","total","currency","shippingAddress","version","createdAt","updatedAt"]},"OrderListAdminResponseDto":{"type":"object","properties":{"orders":{"description":"List of orders (admin runtime shape)","type":"array","items":{"$ref":"#/components/schemas/OrderResponseDto"}},"total":{"type":"number","description":"Total number of orders matching filters"}},"required":["orders","total"]},"UpdateOrderStatusDto":{"type":"object","properties":{"status":{"description":"New order status","allOf":[{"$ref":"#/components/schemas/OrderStatus"}]},"reason":{"type":"string","description":"Status change reason"},"notifyCustomer":{"type":"boolean","description":"Notify customer about status change","default":true}},"required":["status"]},"UpdateFulfillmentStatusDto":{"type":"object","properties":{"fulfillmentStatus":{"description":"New fulfillment status","allOf":[{"$ref":"#/components/schemas/FulfillmentStatus"}]}},"required":["fulfillmentStatus"]},"CancelOrderDto":{"type":"object","properties":{"reason":{"type":"string","description":"Cancellation reason"}}},"UpdateTagsDto":{"type":"object","properties":{"tags":{"description":"Tags to set on order","type":"array","items":{"type":"string"}}},"required":["tags"]},"CustomerStatus":{"type":"string","enum":["ACTIVE","INACTIVE","BLOCKED","PENDING_APPROVAL"]},"MerchantCustomerOrderBy":{"type":"string","enum":["createdAt","updatedAt","email","totalSpent"]},"CustomerAddressResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Address ID"},"firstName":{"type":"string","description":"First name"},"lastName":{"type":"string","description":"Last name"},"company":{"type":"string","description":"Company name","nullable":true},"address1":{"type":"string","description":"Address line 1"},"address2":{"type":"string","description":"Address line 2","nullable":true},"buildingNumber":{"type":"string","description":"Building / house number","nullable":true},"flatNumber":{"type":"string","description":"Flat / apartment number","nullable":true},"city":{"type":"string","description":"City"},"state":{"type":"string","description":"State/Province","nullable":true},"postalCode":{"type":"string","description":"Postal code"},"country":{"type":"string","description":"Country code"},"phone":{"type":"string","description":"Phone number","nullable":true},"label":{"type":"string","description":"Address label","nullable":true},"isDefaultShipping":{"type":"boolean","description":"Is default shipping address"},"isDefaultBilling":{"type":"boolean","description":"Is default billing address"},"taxId":{"type":"string","description":"NIP for billing address","nullable":true},"vatNumber":{"type":"string","description":"VAT EU for billing address","nullable":true}},"required":["id","firstName","lastName","address1","city","postalCode","country","isDefaultShipping","isDefaultBilling"]},"CustomerType":{"type":"string","enum":["INDIVIDUAL","COMPANY"],"description":"Customer type: INDIVIDUAL or COMPANY"},"AcquisitionSource":{"type":"string","enum":["REGISTRATION","GUEST_CHECKOUT","MANUAL_ORDER","IMPORT","MARKETPLACE","CAMPAIGN","REFERRAL","OTHER"],"description":"Source of customer acquisition"},"CustomerOwnerDto":{"type":"object","properties":{"id":{"type":"string","description":"Owner ID"},"firstName":{"type":"string","description":"Owner first name"},"lastName":{"type":"string","description":"Owner last name"},"email":{"type":"string","description":"Owner email"}},"required":["id"]},"CustomerResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Customer ID"},"email":{"type":"string","description":"Customer email"},"firstName":{"type":"string","description":"First name","nullable":true},"lastName":{"type":"string","description":"Last name","nullable":true},"phone":{"type":"string","description":"Phone number","nullable":true},"isGuest":{"type":"boolean","description":"Is guest customer (checkout without account)"},"emailVerified":{"type":"boolean","description":"Is email verified"},"isAnonymized":{"type":"boolean","description":"GDPR-anonymized customer (derived from the anonymized e-mail pattern — the address is not a real mailbox, so e-mail actions are unavailable)"},"status":{"allOf":[{"$ref":"#/components/schemas/CustomerStatus"}]},"emailMarketingState":{"type":"string","description":"Email marketing consent state","enum":["NOT_SUBSCRIBED","PENDING","SUBSCRIBED","UNSUBSCRIBED","REDACTED","INVALID"]},"emailOptInLevel":{"type":"string","description":"Email opt-in level","enum":["UNKNOWN","SINGLE_OPT_IN","CONFIRMED_OPT_IN"]},"emailConsentUpdatedAt":{"type":"string","description":"When email consent was last updated","format":"date-time"},"smsMarketingState":{"type":"string","description":"SMS marketing consent state","enum":["NOT_SUBSCRIBED","PENDING","SUBSCRIBED","UNSUBSCRIBED","REDACTED","INVALID"]},"orderUpdatesEnabled":{"type":"boolean","description":"Whether order update emails are enabled"},"locale":{"type":"string","description":"Customer locale/language preference"},"totalOrders":{"type":"number","description":"Total orders count"},"totalSpent":{"type":"number","description":"Total spent in cents"},"averageOrderValue":{"type":"number","description":"Average order value in cents"},"lifetimeValue":{"type":"number","description":"Lifetime value in cents"},"firstOrderAt":{"type":"string","description":"First order date","format":"date-time"},"lastOrderAt":{"type":"string","description":"Last order date","format":"date-time"},"tags":{"description":"Customer tags","type":"array","items":{"type":"string"}},"customerGroupIds":{"description":"Customer group IDs","type":"array","items":{"type":"string"}},"addresses":{"description":"Customer addresses","type":"array","items":{"$ref":"#/components/schemas/CustomerAddressResponseDto"}},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"},"lastLoginAt":{"type":"string","description":"Last login timestamp","format":"date-time"},"customerType":{"description":"Customer type: INDIVIDUAL or COMPANY","allOf":[{"$ref":"#/components/schemas/CustomerType"}]},"companyName":{"type":"string","description":"Company name","nullable":true},"taxId":{"type":"string","description":"Polish NIP","nullable":true},"vatNumber":{"type":"string","description":"VAT EU number","nullable":true},"regon":{"type":"string","description":"REGON","nullable":true},"taxExemptionStatus":{"type":"string","description":"Tax exemption status: NONE, PENDING, or EXEMPT","enum":["NONE","PENDING","EXEMPT"]},"customFields":{"type":"object","description":"Values of store-defined registration form fields (forms engine), keyed by field key. Shown in the panel when reviewing a pending account.","additionalProperties":true},"acquisitionSource":{"description":"Source of customer acquisition","allOf":[{"$ref":"#/components/schemas/AcquisitionSource"}]},"campaignName":{"type":"string","description":"Campaign name","nullable":true},"referralCode":{"type":"string","description":"Referral code","nullable":true},"ownerId":{"type":"string","description":"Owner/staff member ID","nullable":true},"owner":{"description":"Owner details","allOf":[{"$ref":"#/components/schemas/CustomerOwnerDto"}]},"notes":{"type":"string","description":"Internal notes","nullable":true},"consents":{"type":"object","description":"Communication preferences/consents","additionalProperties":{"type":"boolean"}}},"required":["id","email","isGuest","emailVerified","isAnonymized","status","emailMarketingState","emailOptInLevel","smsMarketingState","orderUpdatesEnabled","locale","totalOrders","totalSpent","averageOrderValue","lifetimeValue","tags","createdAt","updatedAt","customerType","taxExemptionStatus"]},"CustomerListResponseDto":{"type":"object","properties":{"customers":{"description":"List of customers matching the query filters.","type":"array","items":{"$ref":"#/components/schemas/CustomerResponseDto"}},"total":{"type":"number","description":"Total number of customers matching the filters (before pagination).","example":42}},"required":["customers","total"]},"EmailMarketingState":{"type":"string","enum":["NOT_SUBSCRIBED","PENDING","SUBSCRIBED","UNSUBSCRIBED","REDACTED","INVALID"],"description":"Initial email marketing consent state"},"AdminCreateCustomerDto":{"type":"object","properties":{"email":{"type":"string","description":"Customer email"},"firstName":{"type":"string","description":"First name"},"lastName":{"type":"string","description":"Last name"},"phone":{"type":"string","description":"Phone number"},"locale":{"type":"string","description":"Customer locale"},"status":{"allOf":[{"$ref":"#/components/schemas/CustomerStatus"}]},"tags":{"description":"Customer tags","type":"array","items":{"type":"string"}},"customerGroupIds":{"description":"Customer group IDs","type":"array","items":{"type":"string"}},"customerType":{"allOf":[{"$ref":"#/components/schemas/CustomerType"}]},"companyName":{"type":"string","description":"Company name"},"taxId":{"type":"string","description":"Tax ID (NIP for Poland, 10 digits with checksum)"},"vatNumber":{"type":"string","description":"VAT EU number (e.g., PL1234567890)"},"regon":{"type":"string","description":"REGON (9 or 14 digits with checksum)"},"acquisitionSource":{"allOf":[{"$ref":"#/components/schemas/AcquisitionSource"}]},"campaignName":{"type":"string","description":"Campaign name"},"referralCode":{"type":"string","description":"Referral code"},"ownerId":{"type":"string","description":"Owner ID"},"notes":{"type":"string","description":"Internal notes"},"consents":{"type":"object","description":"Communication consents — typed subset shared with importers (ImportConsentPreferences) and admin UI. Currently emailMarketing and smsMarketing; extend explicitly when adding new channels.","additionalProperties":{"type":"boolean"}},"emailMarketingState":{"description":"Initial email marketing consent state","allOf":[{"$ref":"#/components/schemas/EmailMarketingState"}]}},"required":["email"]},"UpdateCustomerDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name"},"lastName":{"type":"string","description":"Last name"},"phone":{"type":"string","description":"Phone number"},"locale":{"type":"string","description":"Customer locale"},"status":{"allOf":[{"$ref":"#/components/schemas/CustomerStatus"}]},"tags":{"description":"Customer tags","type":"array","items":{"type":"string"}},"customerGroupIds":{"description":"Customer group IDs","type":"array","items":{"type":"string"}},"customerType":{"description":"Customer type: INDIVIDUAL or COMPANY","default":"INDIVIDUAL","allOf":[{"$ref":"#/components/schemas/CustomerType"}]},"companyName":{"type":"string","description":"Company name (required for COMPANY type)"},"taxId":{"type":"string","description":"Tax ID (NIP for Poland, 10 digits with checksum)"},"vatNumber":{"type":"string","description":"VAT EU number (e.g., PL1234567890, DE123456789)"},"regon":{"type":"string","description":"Business registry number (REGON for Poland, 9 or 14 digits with checksum)"},"acquisitionSource":{"description":"Source of customer acquisition","allOf":[{"$ref":"#/components/schemas/AcquisitionSource"}]},"campaignName":{"type":"string","description":"Campaign name (for CAMPAIGN acquisition source)"},"referralCode":{"type":"string","description":"Referral code (for REFERRAL acquisition source)"},"ownerId":{"type":"string","description":"Owner/staff member ID (UUID)"},"notes":{"type":"string","description":"Internal notes about the customer"},"consents":{"type":"object","description":"Communication preferences/consents (JSON object)","additionalProperties":{"type":"boolean"}},"emailMarketingState":{"type":"string","description":"Email marketing state (admin change — delegated to CustomerConsentService)","enum":["SUBSCRIBED","UNSUBSCRIBED","NOT_SUBSCRIBED"]},"smsMarketingState":{"type":"string","description":"SMS marketing state","enum":["SUBSCRIBED","UNSUBSCRIBED","NOT_SUBSCRIBED"]},"orderUpdatesEnabled":{"type":"boolean","description":"Whether customer receives order update notifications"}}},"CustomerDeletionFilterDto":{"type":"object","properties":{"importJobId":{"type":"string","description":"Restrict to customers created by this specific import job."},"createdBefore":{"type":"string","description":"Restrict to customers created strictly before this ISO 8601 timestamp."}}},"MerchantBulkDeleteCustomersDto":{"type":"object","properties":{"ids":{"description":"Explicit customer IDs (1-500). Takes precedence over `filter`. Non-eligible IDs are skipped.","type":"array","items":{"type":"string"}},"filter":{"description":"Filter selecting eligible import customers (used when `ids` is absent; empty = all eligible).","allOf":[{"$ref":"#/components/schemas/CustomerDeletionFilterDto"}]}}},"CustomerDeletionSampleDto":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"createdAt":{"type":"string","description":"ISO 8601 creation timestamp."}},"required":["id","email","createdAt"]},"BulkDeletePreviewDto":{"type":"object","properties":{"hardEligibleCount":{"type":"number","description":"Customers that will be permanently hard-deleted (import-sourced, no history)."},"blockedCount":{"type":"number","description":"Customers that will be anonymized/skipped instead (have blocking history or not import-sourced)."},"notFoundCount":{"type":"number","description":"Requested IDs not found in this shop."},"sample":{"type":"array","items":{"$ref":"#/components/schemas/CustomerDeletionSampleDto"}},"estimatedDurationSecs":{"type":"number","description":"Rough estimated processing duration in seconds."}},"required":["hardEligibleCount","blockedCount","notFoundCount","sample","estimatedDurationSecs"]},"CustomerDeletionJobStatus":{"type":"string","enum":["PENDING","RUNNING","COMPLETED","COMPLETED_WITH_ERRORS","FAILED","CANCELLED"]},"CustomerDeletionJobResponseDto":{"type":"object","properties":{"jobId":{"type":"string"},"status":{"allOf":[{"$ref":"#/components/schemas/CustomerDeletionJobStatus"}]},"totalRequested":{"type":"number"},"processed":{"type":"number"},"hardDeleted":{"type":"number"},"anonymized":{"type":"number"},"skipped":{"type":"number"},"failed":{"type":"number"},"startedAt":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 start timestamp."},"completedAt":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 completion timestamp."}},"required":["jobId","status","totalRequested","processed","hardDeleted","anonymized","skipped","failed"]},"MerchantInventorySortBy":{"type":"string","enum":["productName","sku","stock","reserved","available","createdAt","updatedAt"]},"InventoryVariantItemDto":{"type":"object","properties":{"variantId":{"type":"string","description":"Product variant UUID."},"productId":{"type":"string","description":"Parent product UUID."},"productName":{"type":"string","description":"Parent product name."},"variantName":{"type":"string","description":"Product variant name."},"sku":{"type":"string","description":"Variant SKU code."},"stock":{"type":"number","description":"Total physical quantity on hand (sum across all queried locations)."},"reserved":{"type":"number","description":"Total reserved quantity (checkout holds)."},"available":{"type":"number","description":"Total available quantity for sale."},"safetyStock":{"type":"number","description":"Units held back from sale by the merchant (a buffer for returns, display stock and the like) — the third term of `available = on hand − reserved − safety stock`. Scoped to the requested location when `locationId` is given, otherwise summed across active locations. Distinct from `reserved`, which is stock already claimed by carts and orders."},"needsReorder":{"type":"boolean","description":"Whether this row needs reordering — inventory-tracked and either at (or below) its reorder point in an active location, or out of stock entirely. Same rule as the `belowReorder` filter, so a highlighted row and a filtered list always agree. Scoped to the requested location when `locationId` is given."},"imageUrl":{"type":"string","nullable":true,"description":"URL of the variant image thumbnail. Null when no image assigned."},"createdAt":{"type":"string","format":"date-time","description":"When this variant was added to the catalogue."},"updatedAt":{"type":"string","format":"date-time","description":"When this variant was last edited: its own catalogue fields (SKU, price, name, weight…), its option links, its attributes, or a manual stock correction made by a human. Sales, cart reservations and automatic stock recalculation deliberately do NOT move this timestamp, so it answers \"when did someone last work on this row\"."}},"required":["variantId","productId","productName","variantName","sku","stock","reserved","available","safetyStock","needsReorder","createdAt","updatedAt"]},"InventoryVariantsPagedResponseDto":{"type":"object","properties":{"variants":{"description":"Inventory variant rows for current page.","type":"array","items":{"$ref":"#/components/schemas/InventoryVariantItemDto"}},"total":{"type":"number","description":"Total number of variants matching the current filter."}},"required":["variants","total"]},"InventoryOperationType":{"type":"string","enum":["STOCK_IN","STOCK_OUT","ADJUSTMENT_UP","ADJUSTMENT_DOWN","RETURN_IN","DAMAGE_OUT","TRANSFER_IN","TRANSFER_OUT","INITIAL_STOCK","IMPORT_ROLLBACK","SHIPMENT_CANCEL_REVERSAL"],"description":"Operation type"},"ShopLedgerEntryDto":{"type":"object","properties":{"id":{"type":"string","description":"Ledger entry ID"},"variantId":{"type":"string","description":"Variant ID"},"delta":{"type":"number","description":"Stock change (positive = increase, negative = decrease)"},"operationType":{"description":"Operation type","allOf":[{"$ref":"#/components/schemas/InventoryOperationType"}]},"orderId":{"type":"string","description":"Order ID if related to an order"},"reservationId":{"type":"string","description":"Reservation ID if related to a reservation"},"reference":{"type":"string","description":"Reference ID"},"referenceType":{"type":"string","description":"Reference type"},"notes":{"type":"string","description":"Notes"},"createdBy":{"type":"string","description":"User who made the change"},"createdAt":{"type":"string","description":"Timestamp","format":"date-time"},"productName":{"type":"string","description":"Parent product name."},"variantName":{"type":"string","description":"Product variant name."},"sku":{"type":"string","description":"Variant SKU code."},"locationId":{"type":"string","nullable":true,"description":"Inventory location UUID. Null for shop-wide operations without a specific location."},"locationName":{"type":"string","nullable":true,"description":"Inventory location name. Null when location was deleted or operation is shop-wide."}},"required":["id","variantId","delta","operationType","createdAt","productName","variantName","sku"]},"ShopLedgerResponseDto":{"type":"object","properties":{"entries":{"description":"Ledger entries for current page.","type":"array","items":{"$ref":"#/components/schemas/ShopLedgerEntryDto"}},"total":{"type":"number","description":"Total number of ledger entries matching current filters."}},"required":["entries","total"]},"StockInfoResponseDto":{"type":"object","properties":{"stock":{"type":"number","description":"Total physical stock quantity (ledger SUM)."},"reserved":{"type":"number","description":"Reserved quantity (active checkout holds)."},"available":{"type":"number","description":"Physical available: stock - reserved (no safety buffer)."},"safetyStock":{"type":"number","description":"Safety stock buffer (sum across the variant locations)."},"rawAvailable":{"type":"number","description":"Sellable available (signed): stock - reserved - safety stock. Sell gates check this."}},"required":["stock","reserved","available","safetyStock","rawAvailable"]},"StockAdjustmentOperation":{"type":"string","enum":["increase","decrease","set"],"description":"Operation type"},"AdjustStockDto":{"type":"object","properties":{"quantity":{"type":"number","description":"Quantity to adjust","example":10,"minimum":0},"operation":{"description":"Operation type","example":"increase","allOf":[{"$ref":"#/components/schemas/StockAdjustmentOperation"}]},"reason":{"type":"string","description":"Reason for adjustment","example":"Received new shipment"},"locationId":{"type":"string","description":"Location ID for the adjustment. If not provided, defaults to shop default location.","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["quantity","operation"]},"StockAdjustmentResultResponseDto":{"type":"object","properties":{"stock":{"type":"number","description":"New stock quantity"},"available":{"type":"number","description":"New available quantity"}},"required":["stock","available"]},"MerchantBrandOrderBy":{"type":"string","enum":["name","createdAt","updatedAt","productCount"]},"BrandResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Brand ID"},"name":{"type":"string","description":"Brand name"},"slug":{"type":"string","description":"URL-friendly slug"},"description":{"type":"string","description":"Brand description","nullable":true},"logo":{"type":"string","description":"Logo URL","nullable":true},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"translations":{"type":"object","additionalProperties":true},"isActive":{"type":"boolean","description":"Is brand active"},"productCount":{"type":"number","description":"Number of active products assigned to this brand (cached aggregation)"},"createdBy":{"type":"string","description":"Created by user ID"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","slug","description","logo","metaTitle","metaDescription","translations","isActive","productCount","createdBy","createdAt","updatedAt"]},"PaginatedBrandResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BrandResponseDto"}},"meta":{"type":"object","additionalProperties":true}},"required":["data","meta"]},"CreateBrandDto":{"type":"object","properties":{"name":{"type":"string","description":"Brand name (canonical w shop base language)","maxLength":255,"example":"Funko"},"slug":{"type":"string","description":"URL-friendly slug (unique per shop). Lowercase, alphanumeric and hyphens.","maxLength":255,"example":"funko"},"description":{"type":"string","description":"Long-form description (HTML allowed)","example":"Producent kolekcjonerskich figurek pop culture."},"logo":{"type":"string","description":"Brand logo URL (R2/CDN; storefront-rendered). Wymagany scheme http(s):// — blokuje javascript:/data: dla defense-in-depth.","example":"https://cdn.doswiftly.pl/brands/funko-logo.svg"},"metaTitle":{"type":"string","description":"SEO meta title (canonical lang fallback)","maxLength":255},"metaDescription":{"type":"string","description":"SEO meta description (canonical lang fallback)","maxLength":500},"translations":{"type":"object","description":"Multi-language overrides: `{ pl: { name, description, metaTitle, metaDescription }, en: {...} }`","additionalProperties":true},"isActive":{"type":"boolean","description":"Czy brand jest aktywny (storefront filtruje po isActive=true)","default":true}},"required":["name","slug"]},"UpdateBrandDto":{"type":"object","properties":{"name":{"type":"string","description":"Brand name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Brand description"},"logo":{"type":"string","description":"Logo URL (http(s)://)"},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"},"translations":{"type":"object","additionalProperties":true},"isActive":{"type":"boolean","description":"Is brand active"}}},"BrandDeleteResultDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the deleted brand."}},"required":["id"]},"ProductVariantResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Variant ID"},"productId":{"type":"string","description":"Product ID"},"sku":{"type":"string","description":"Stock Keeping Unit"},"barcode":{"type":"string","description":"Barcode","nullable":true},"name":{"type":"string","description":"Variant name"},"attributes":{"type":"object","description":"Variant attributes","additionalProperties":true},"optionValues":{"type":"object","description":"Option values","additionalProperties":{"type":"string"}},"price":{"type":"number","description":"Price in cents"},"compareAtPrice":{"type":"number","description":"Compare at price","nullable":true},"costPrice":{"type":"number","description":"Cost price","nullable":true},"currency":{"type":"string","description":"Currency code"},"weight":{"type":"number","description":"Weight in grams","nullable":true},"dimensions":{"type":"object","description":"Variant dimensions","additionalProperties":true,"nullable":true},"requiresShipping":{"type":"boolean","description":"Requires shipping"},"stock":{"type":"number","description":"Current stock"},"reserved":{"type":"number","description":"Reserved stock"},"available":{"type":"number","description":"Available stock (stock - reserved)"},"availability":{"description":"Read model: variant stock availability resolved through the full variant ?? product ?? shop policy chain. UNTRACKED = inventory not tracked, IN_STOCK = units available, BACKORDER = sellable while depleted, OUT_OF_STOCK = nothing to sell. Present only on the product-list projection (includeVariants).","allOf":[{"$ref":"#/components/schemas/StockAvailability"}]},"version":{"type":"number","description":"Optimistic lock version"},"trackQuantity":{"type":"boolean","description":"Track inventory. null = inherit from global settings","nullable":true},"allowBackorder":{"type":"boolean","description":"Allow backorders. null = inherit from global settings","nullable":true},"minReorderPoint":{"type":"number","description":"Minimum reorder point across active locations (null if none set). Present only on the product read, which knows the shop threshold it inherits from.","nullable":true},"safetyStock":{"type":"number","description":"Effective safety buffer summed across active locations — the units withheld from sale (available = stock - reserved - safetyStock)."},"isActive":{"type":"boolean","description":"Is variant active"},"isDefault":{"type":"boolean","description":"Is this the default variant for the product"},"taxClassId":{"type":"string","description":"Tax class ID (null = inherit from product)","nullable":true},"selectedOptionValueIds":{"description":"Option value IDs picked for this variant. Empty for a variant without options.","type":"array","items":{"type":"string"}},"images":{"description":"Variant image URLs","type":"array","items":{"type":"string"}},"translations":{"type":"object","description":"Translations by locale","additionalProperties":true},"createdBy":{"type":"string","description":"Created by user ID","nullable":true},"updatedBy":{"type":"string","description":"Updated by user ID","nullable":true},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","productId","sku","barcode","name","attributes","optionValues","price","compareAtPrice","costPrice","currency","weight","dimensions","requiresShipping","stock","reserved","available","version","trackQuantity","allowBackorder","isActive","isDefault","taxClassId","selectedOptionValueIds","createdBy","updatedBy","createdAt","updatedAt"]},"CreateProductVariantDto":{"type":"object","properties":{"sku":{"type":"string","description":"Stock Keeping Unit (unique identifier)","maxLength":100},"barcode":{"type":"string","description":"Barcode (EAN, UPC, etc.)","maxLength":100},"name":{"type":"string","description":"Variant name","maxLength":255},"attributes":{"type":"object","description":"Variant attributes (e.g., color, size)","additionalProperties":true},"optionValues":{"type":"object","description":"[Deprecated] Legacy JSON option values","additionalProperties":{"type":"string"}},"selectedOptionValueIds":{"description":"IDs of ProductOptionValue rows chosen for this variant","type":"array","items":{"type":"string"}},"price":{"type":"number","description":"Price in cents","minimum":0},"compareAtPrice":{"type":"number","description":"Compare at price in cents"},"costPrice":{"type":"number","description":"Cost price in cents"},"currency":{"type":"string","description":"Currency code. Omitted = the shop sales currency."},"weight":{"type":"number","description":"Weight in grams"},"dimensions":{"description":"Variant dimensions","allOf":[{"$ref":"#/components/schemas/DimensionsDto"}]},"requiresShipping":{"type":"boolean","description":"Requires shipping"},"stock":{"type":"number","description":"Initial stock quantity"},"trackQuantity":{"type":"boolean","description":"Track inventory quantity. null = inherit from global settings, true/false = explicit override","nullable":true},"allowBackorder":{"type":"boolean","description":"Allow backorders. null = inherit from global settings, true/false = explicit override","nullable":true},"taxClassId":{"type":"string","description":"Tax class ID (null = inherit from product)","nullable":true},"images":{"description":"Variant images URLs","type":"array","items":{"type":"string"}},"translations":{"type":"object","description":"Translations by locale","additionalProperties":true}},"required":["sku","name","price"]},"UpdateProductVariantDto":{"type":"object","properties":{"sku":{"type":"string","description":"Stock Keeping Unit","maxLength":100},"barcode":{"type":"string","description":"Barcode","maxLength":100},"name":{"type":"string","description":"Variant name","maxLength":255},"attributes":{"type":"object","description":"Variant attributes","additionalProperties":true},"optionValues":{"type":"object","description":"[Deprecated] Legacy JSON option values","additionalProperties":{"type":"string"}},"selectedOptionValueIds":{"description":"IDs of ProductOptionValue rows chosen for this variant","type":"array","items":{"type":"string"}},"price":{"type":"number","description":"Price in cents"},"compareAtPrice":{"type":"number","description":"Compare at price in cents. null clears the column (removes the sale price)","nullable":true},"costPrice":{"type":"number","description":"Cost price in cents. null clears the column","nullable":true},"currency":{"type":"string","description":"Currency code"},"weight":{"type":"number","description":"Weight in grams. null clears the column","nullable":true},"dimensions":{"description":"Variant dimensions. null clears the column","nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/DimensionsDto"}]},"requiresShipping":{"type":"boolean","description":"Requires shipping"},"trackQuantity":{"type":"boolean","description":"Track inventory quantity. null = inherit from global settings, true/false = explicit override","nullable":true},"allowBackorder":{"type":"boolean","description":"Allow backorders. null = inherit from global settings, true/false = explicit override","nullable":true},"isActive":{"type":"boolean","description":"Is variant active"},"taxClassId":{"type":"string","description":"Tax class ID (null = inherit from product)","nullable":true},"images":{"description":"Variant images URLs","type":"array","items":{"type":"string"}},"translations":{"type":"object","description":"Translations by locale","additionalProperties":true}}},"ImageStatus":{"type":"string","enum":["PENDING","UPLOADING","PROCESSING","READY","FAILED"],"description":"Processing status of the image. Always PENDING at accept time."},"AsyncImageUploadResultDto":{"type":"object","properties":{"imageId":{"type":"string","description":"Unique identifier of the queued image record.","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"status":{"description":"Processing status of the image. Always PENDING at accept time.","example":"PENDING","allOf":[{"$ref":"#/components/schemas/ImageStatus"}]},"correlationId":{"type":"string","description":"Correlation ID for distributed tracing of this upload task.","format":"uuid","example":"6ba7b810-9dad-11d1-80b4-00c04fd430c8"}},"required":["imageId","status","correlationId"]},"BulkImageUploadResultDto":{"type":"object","properties":{"batchId":{"type":"string","description":"Unique identifier of the batch record tracking this bulk upload.","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440001"},"batchCorrelationId":{"type":"string","description":"Shared correlation ID for tracing all events within this batch.","format":"uuid","example":"6ba7b810-9dad-11d1-80b4-00c04fd430c9"},"images":{"description":"Individual upload results for each image in the batch.","type":"array","items":{"$ref":"#/components/schemas/AsyncImageUploadResultDto"}},"totalCount":{"type":"number","description":"Total number of images accepted in this batch.","example":5}},"required":["batchId","batchCorrelationId","images","totalCount"]},"BatchStatus":{"type":"string","enum":["PROCESSING","COMPLETED","PARTIAL"],"description":"Overall batch processing status. PROCESSING while images are still in queue; COMPLETED when all succeeded; PARTIAL when some failed."},"BatchStatusResponseDto":{"type":"object","properties":{"batchId":{"type":"string","description":"Unique identifier of the batch.","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440001"},"status":{"description":"Overall batch processing status. PROCESSING while images are still in queue; COMPLETED when all succeeded; PARTIAL when some failed.","example":"PROCESSING","allOf":[{"$ref":"#/components/schemas/BatchStatus"}]},"total":{"type":"number","description":"Total number of images in this batch.","example":5},"ready":{"type":"number","description":"Number of images that have been successfully processed (status READY).","example":3},"failed":{"type":"number","description":"Number of images that failed processing.","example":1}},"required":["batchId","status","total","ready","failed"]},"ImageStatusResponseDto":{"type":"object","properties":{"imageId":{"type":"string","description":"Unique identifier of the image.","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"status":{"description":"Current processing status of the image.","example":"READY","allOf":[{"$ref":"#/components/schemas/ImageStatus"}]},"url":{"type":"string","description":"Public CDN URL of the processed image. Present only when status is READY.","example":"https://cdn.doswiftly.pl/products/img-abc123.webp"},"thumbnails":{"type":"object","description":"Map of generated thumbnail variants keyed by size name (e.g. \"small\", \"medium\"). Present only when status is READY.","additionalProperties":{"type":"object"}},"error":{"type":"string","description":"Human-readable error message. Present only when status is FAILED.","example":"Image processing failed: unsupported color profile."},"processingTimeMs":{"type":"number","description":"Time in milliseconds from processing start to completion. Present when processing finished (READY or FAILED).","example":1340}},"required":["imageId","status"]},"ReorderImagesDto":{"type":"object","properties":{"imageIds":{"description":"Array of image IDs in desired order","type":"array","items":{"type":"string"}}},"required":["imageIds"]},"ProductImageDto":{"type":"object","properties":{"id":{"type":"string","description":"Image ID (UUID)"},"url":{"type":"string","description":"Public URL of the image"},"path":{"type":"string","description":"Storage path (for deletion)"},"filename":{"type":"string","description":"Original filename"},"mimeType":{"type":"string","description":"MIME type"},"size":{"type":"number","description":"File size in bytes"},"position":{"type":"number","description":"Display position (0-based)"},"alt":{"type":"string","description":"Alt text for SEO"},"width":{"type":"number","description":"Image width in pixels","nullable":true},"height":{"type":"number","description":"Image height in pixels","nullable":true},"thumbhash":{"type":"string","description":"ThumbHash placeholder (base64-encoded, ~40 chars)","nullable":true},"thumbnails":{"type":"object","description":"Generated thumbnails keyed by size name (small, medium, large, thumbnail)","additionalProperties":true},"createdAt":{"type":"string","description":"Upload timestamp"}},"required":["id","url","path","filename","mimeType","size","position","createdAt"]},"AttributeType":{"type":"string","enum":["TEXT","TEXTAREA","SELECT","CHECKBOX","RADIO","IMAGE","FILE","NUMBER","CURRENCY","DATE","DATE_TIME","BOOLEAN","COLOR","JSON","URL"]},"MerchantAttributeOrderBy":{"type":"string","enum":["name","displayOrder","createdAt","updatedAt"]},"MerchantAttributeOrderDir":{"type":"string","enum":["asc","desc"]},"AttributeFillingMode":{"type":"string","enum":["MERCHANT","CUSTOMER","BOTH"],"description":"Who fills the value: MERCHANT (metadata attribute), CUSTOMER or BOTH (configurator field)."},"AttributeBillingMode":{"type":"string","enum":["BUNDLED","SEPARATE_LINE"],"description":"How option surcharges affect pricing. NULL = informational only (no price effect)."},"AttributeOptionSurchargeType":{"type":"string","enum":["FIXED","PERCENT"],"description":"Surcharge calculation type."},"AttributeOptionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Option ID"},"value":{"type":"string","description":"Option value (internal)"},"label":{"type":"string","description":"Option label (display)"},"sortOrder":{"type":"number","description":"Sort order"},"colorHex":{"type":"string","description":"Color hex value","nullable":true},"surchargeAmount":{"type":"number","nullable":true,"description":"Surcharge when this option is selected. NULL = no surcharge. Unit depends on surchargeType: FIXED = minor currency units; PERCENT = thousandths of percent (1000 = 10.00%)."},"surchargeType":{"nullable":true,"description":"Surcharge calculation type.","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Whether this option is pre-selected by default."},"linkedVariantId":{"type":"string","format":"uuid","nullable":true,"description":"Linked ProductVariant sold as a stocked component when this option is selected."},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","value","label","sortOrder","createdAt","updatedAt"]},"AttributeVisibilityConditionDto":{"type":"object","properties":{"attributeDefinitionId":{"type":"string","format":"uuid","description":"Definition whose answer controls visibility (the parent field in a component tree)."},"operator":{"type":"string","enum":["EQUALS","NOT_EQUALS","ONE_OF"],"description":"EQUALS/ONE_OF with optionIds: visible when ANY listed option is selected. NOT_EQUALS: visible when NONE is selected."},"optionIds":{"description":"Option ids of the referenced definition (for SELECT/RADIO/CHECKBOX parents).","type":"array","items":{"type":"string"}},"value":{"type":"string","description":"Answer to compare against for option-less parents (TEXT/NUMBER/BOOLEAN as string)."}},"required":["attributeDefinitionId","operator"]},"AttributeDefinitionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Attribute ID"},"name":{"type":"string","description":"Attribute name"},"slug":{"type":"string","description":"URL-friendly slug"},"type":{"description":"Attribute type","allOf":[{"$ref":"#/components/schemas/AttributeType"}]},"description":{"type":"string","description":"Attribute description"},"defaultValue":{"type":"object","description":"Default value","additionalProperties":true},"isVisible":{"type":"boolean","description":"Is visible on product page"},"isFilterable":{"type":"boolean","description":"Can be used for filtering"},"isRequired":{"type":"boolean","description":"Is required for products"},"isLocalized":{"type":"boolean","description":"Supports localization"},"affectsPrice":{"type":"boolean","description":"Affects product price (used for variant generation)"},"displayOrder":{"type":"number","description":"Display order"},"minValue":{"type":"number","description":"Minimum value (for NUMBER type)"},"maxValue":{"type":"number","description":"Maximum value (for NUMBER type)"},"fillingMode":{"description":"Who fills the value: MERCHANT (metadata attribute), CUSTOMER or BOTH (configurator field).","allOf":[{"$ref":"#/components/schemas/AttributeFillingMode"}]},"billingMode":{"description":"How option surcharges affect pricing. NULL = informational only (no price effect).","nullable":true,"allOf":[{"$ref":"#/components/schemas/AttributeBillingMode"}]},"taxClassId":{"type":"string","format":"uuid","nullable":true,"description":"Tax class for surcharges. NULL = inherit from the variant."},"scopeProductId":{"type":"string","format":"uuid","nullable":true,"description":"Product this definition is scoped to. NULL = global (usable in attribute sets)."},"options":{"description":"Predefined options","type":"array","items":{"$ref":"#/components/schemas/AttributeOptionResponseDto"}},"productCount":{"type":"number","description":"Number of products using this attribute"},"showIfConditions":{"description":"Visibility conditions (AND); null/absent = field always visible.","nullable":true,"type":"array","items":{"$ref":"#/components/schemas/AttributeVisibilityConditionDto"}},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","name","slug","type","isVisible","isFilterable","isRequired","isLocalized","affectsPrice","displayOrder","options","productCount","createdAt","updatedAt"]},"PaginationMetaDto":{"type":"object","properties":{"total":{"type":"number","description":"Total number of items"},"page":{"type":"number","description":"Current page number"},"limit":{"type":"number","description":"Items per page"},"totalPages":{"type":"number","description":"Total number of pages"}},"required":["total","page","limit","totalPages"]},"PaginatedAttributeResponseDto":{"type":"object","properties":{"data":{"description":"Array of attributes","type":"array","items":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"MerchantAttributeOptionDto":{"type":"object","properties":{"value":{"type":"string","description":"Option value (internal)","maxLength":255},"label":{"type":"string","description":"Option label (display)","maxLength":255},"sortOrder":{"type":"number","description":"Sort order","default":0},"colorHex":{"type":"string","description":"Color hex value (for COLOR type)","maxLength":7},"isDefault":{"type":"boolean","description":"Default option marker — at most 1 per definition","default":false}},"required":["value","label"]},"MerchantCreateAttributeDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug (auto-generated if not provided)","maxLength":255},"type":{"description":"Attribute type","allOf":[{"$ref":"#/components/schemas/AttributeType"}]},"description":{"type":"string","description":"Attribute description"},"defaultValue":{"type":"object","description":"Default value (JSON)","additionalProperties":true},"isVisible":{"type":"boolean","description":"Is visible on product page","default":true},"isFilterable":{"type":"boolean","description":"Can be used for filtering","default":false},"isRequired":{"type":"boolean","description":"Is required for products","default":false},"isLocalized":{"type":"boolean","description":"Supports localization","default":false},"displayOrder":{"type":"number","description":"Display order","default":0},"minValue":{"type":"number","description":"Minimum value (for NUMBER type)"},"maxValue":{"type":"number","description":"Maximum value (for NUMBER type)"},"namespace":{"type":"string","description":"Optional grouping namespace (e.g. \"inventory\", \"marketing\", \"content\"). NULL = ungrouped.","maxLength":64,"nullable":true},"options":{"description":"Predefined options for SELECT/CHECKBOX/RADIO attribute types.","type":"array","items":{"$ref":"#/components/schemas/MerchantAttributeOptionDto"}}},"required":["name","type"]},"MerchantAttributeOptionSyncDto":{"type":"object","properties":{"id":{"type":"string","description":"Option ID (for existing options)"},"value":{"type":"string","description":"Option value (internal)","maxLength":255},"label":{"type":"string","description":"Option label (display)","maxLength":255},"sortOrder":{"type":"number","description":"Sort order","default":0},"colorHex":{"type":"string","description":"Color hex value (for COLOR type)","maxLength":7},"isDefault":{"type":"boolean","description":"Default option marker"}},"required":["value","label"]},"MerchantUpdateAttributeDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Attribute description"},"defaultValue":{"type":"object","description":"Default value (JSON)","additionalProperties":true},"isVisible":{"type":"boolean","description":"Is visible on product page"},"isFilterable":{"type":"boolean","description":"Can be used for filtering"},"isRequired":{"type":"boolean","description":"Is required for products"},"isLocalized":{"type":"boolean","description":"Supports localization"},"displayOrder":{"type":"number","description":"Display order"},"minValue":{"type":"number","description":"Minimum value (for NUMBER type)"},"maxValue":{"type":"number","description":"Maximum value (for NUMBER type)"},"namespace":{"type":"string","description":"Optional grouping namespace (e.g. \"inventory\"). NULL = ungrouped.","maxLength":64,"nullable":true},"options":{"description":"Options to sync (for SELECT/CHECKBOX/RADIO) — replaces all existing options.","type":"array","items":{"$ref":"#/components/schemas/MerchantAttributeOptionSyncDto"}}}},"DeleteAttributeResultDto":{"type":"object","properties":{"deletedProductAttributesCount":{"type":"number","description":"Number of product attribute value records deleted as part of the attribute removal.","example":42}},"required":["deletedProductAttributesCount"]},"CategoryResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Category ID"},"name":{"type":"string","description":"Category name"},"slug":{"type":"string","description":"URL-friendly slug"},"description":{"type":"string","description":"Category description","nullable":true},"parentId":{"type":"string","description":"Parent category ID","nullable":true},"level":{"type":"number","description":"Hierarchy level (0 = root)"},"path":{"type":"string","description":"Full path (slug/child-slug)"},"sortOrder":{"type":"number","description":"Sort order"},"isActive":{"type":"boolean","description":"Is category active"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"imageUrl":{"type":"string","description":"Category image URL","nullable":true},"translations":{"type":"object","description":"Translations by locale","additionalProperties":true},"productCount":{"type":"number","description":"Number of products in category"},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"},"children":{"description":"Child categories","type":"array","items":{"$ref":"#/components/schemas/CategoryResponseDto"}}},"required":["id","name","slug","level","path","sortOrder","isActive","productCount","createdAt","updatedAt"]},"CreateCategoryDto":{"type":"object","properties":{"name":{"type":"string","description":"Category name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Category description"},"parentId":{"type":"string","description":"Parent category ID for hierarchical structure","format":"uuid"},"sortOrder":{"type":"number","description":"Sort order","default":0},"isActive":{"type":"boolean","description":"Is category active","default":true},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"},"imageUrl":{"type":"string","description":"Category image URL"},"translations":{"type":"object","description":"Translations by locale (key = locale code)","additionalProperties":true}},"required":["name","slug"]},"UpdateCategoryDto":{"type":"object","properties":{"name":{"type":"string","description":"Category name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Category description","nullable":true},"parentId":{"type":"string","description":"Parent category ID","format":"uuid","nullable":true},"sortOrder":{"type":"number","description":"Sort order"},"isActive":{"type":"boolean","description":"Is category active"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"imageUrl":{"type":"string","description":"Category image URL","nullable":true},"translations":{"type":"object","description":"Translations by locale (key = locale code)","additionalProperties":true}}},"ProductAttributeResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Product attribute ID"},"attributeDefinition":{"description":"Attribute definition","allOf":[{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}]},"value":{"type":"object","description":"Attribute value (string, number, boolean, or array based on attribute type)","additionalProperties":true,"nullable":true},"isVisibleOverride":{"type":"boolean","description":"Visibility override","nullable":true},"isLegacyValue":{"type":"boolean","description":"Is legacy value (references deleted option)"},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","attributeDefinition","value","isLegacyValue","createdAt","updatedAt"]},"MerchantSetProductAttributeValueDto":{"type":"object","properties":{"value":{"type":"object","description":"Attribute value. The shape depends on the attribute type: TEXT/TEXTAREA → string; NUMBER → number; BOOLEAN → boolean; DATE → ISO date string; SELECT/RADIO → option value (string); CHECKBOX → array of option values (string[]); COLOR → \"#RRGGBB\" string.","additionalProperties":true,"nullable":true},"isVisibleOverride":{"type":"boolean","description":"Override storefront visibility of this value on this product. Omit to inherit the attribute default.","nullable":true}},"required":["value"]},"MerchantAnalyticsPeriodDto":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"Start of the reporting window (inclusive, ISO 8601)."},"to":{"type":"string","format":"date-time","description":"End of the reporting window (inclusive, ISO 8601)."}},"required":["from","to"]},"MerchantAnalyticsSalesDto":{"type":"object","properties":{"revenue":{"type":"number","description":"Confirmed revenue in minor units (paid/processing/on-hold/completed orders)."},"orders":{"type":"number","description":"Number of revenue orders in the period."},"averageOrderValue":{"type":"number","description":"Average order value in minor units (revenue / orders; 0 when no orders)."},"revenueDelta":{"type":"number","nullable":true,"description":"Revenue change vs the previous period of equal length, in percent. Present only with compareWith=previous."},"ordersDelta":{"type":"number","nullable":true,"description":"Orders change vs the previous period, in percent."},"averageOrderValueDelta":{"type":"number","nullable":true,"description":"Average order value change vs the previous period, in percent."}},"required":["revenue","orders","averageOrderValue"]},"MerchantAnalyticsCartsDto":{"type":"object","properties":{"active":{"type":"number","description":"Carts currently active (created in the period)."},"abandoned":{"type":"number","description":"Carts abandoned."},"converted":{"type":"number","description":"Carts converted into an order."},"recovered":{"type":"number","description":"Abandoned carts later recovered."},"expired":{"type":"number","description":"Carts expired."},"total":{"type":"number","description":"Total carts created in the period."},"abandonmentRate":{"type":"number","description":"Abandoned / total, in percent."},"conversionRate":{"type":"number","description":"Converted / total, in percent."},"abandonedValue":{"type":"number","description":"Total value of abandoned carts in minor units (recoverable revenue)."}},"required":["active","abandoned","converted","recovered","expired","total","abandonmentRate","conversionRate","abandonedValue"]},"MerchantAnalyticsCustomersDto":{"type":"object","properties":{"newCustomers":{"type":"number","description":"Customers created in the period."},"total":{"type":"number","description":"Total customers all-time."}},"required":["newCustomers","total"]},"MerchantAnalyticsFulfillmentDto":{"type":"object","properties":{"fulfillmentRate":{"type":"number","description":"Shipped orders / total orders in the period, in percent."},"averageFulfillmentTimeHours":{"type":"number","description":"Average hours from a confirmed order to its first shipment."},"pendingFulfillmentCount":{"type":"number","description":"Orders awaiting fulfillment (confirmed/processing, no shipment yet)."}},"required":["fulfillmentRate","averageFulfillmentTimeHours","pendingFulfillmentCount"]},"MerchantAnalyticsCatalogDto":{"type":"object","properties":{"activeProducts":{"type":"number","description":"Active products."},"lowStock":{"type":"number","description":"Product variants that need restocking — stock-tracked, active variants whose quantity available to sell across the whole shop has reached the reorder point set for them, or has run out. Counted once per variant: a variant stocked in several warehouses counts once, not once per warehouse. Changed on 2026-08-08 — this used to count warehouse stock records, so a multi-warehouse shop now reports a lower number for the same stock situation, and variants sold without stock control are no longer counted at all."},"outOfStock":{"type":"number","description":"Stock-tracked, active variants with nothing left to sell (quantity available to sell at or below zero). Changed on 2026-08-08 — inactive variants are no longer counted, and a variant that takes its stock-control setting from its product or from the shop is now judged by that resolved setting rather than by its own blank one."}},"required":["activeProducts","lowStock","outOfStock"]},"MerchantAnalyticsTopProductDto":{"type":"object","properties":{"id":{"type":"string","description":"Product ID."},"name":{"type":"string","description":"Product name."},"revenue":{"type":"number","description":"Revenue in minor units for the period."},"unitsSold":{"type":"number","description":"Units sold in the period."}},"required":["id","name","revenue","unitsSold"]},"MerchantAnalyticsSummaryDto":{"type":"object","properties":{"period":{"$ref":"#/components/schemas/MerchantAnalyticsPeriodDto"},"sales":{"$ref":"#/components/schemas/MerchantAnalyticsSalesDto"},"ordersByStatus":{"type":"object","additionalProperties":{"type":"integer"},"description":"Order counts keyed by order status. Every status is present (0 when none).","example":{"CONFIRMED":12,"PENDING":3,"CANCELLED":1,"COMPLETED":40}},"ordersByPaymentStatus":{"type":"object","additionalProperties":{"type":"integer"},"description":"Order counts keyed by payment status. Every status is present (0 when none).","example":{"PAID":50,"PENDING":3,"REFUNDED":2}},"carts":{"$ref":"#/components/schemas/MerchantAnalyticsCartsDto"},"customers":{"$ref":"#/components/schemas/MerchantAnalyticsCustomersDto"},"fulfillment":{"$ref":"#/components/schemas/MerchantAnalyticsFulfillmentDto"},"catalog":{"$ref":"#/components/schemas/MerchantAnalyticsCatalogDto"},"topProducts":{"description":"Top products by revenue in the period.","type":"array","items":{"$ref":"#/components/schemas/MerchantAnalyticsTopProductDto"}},"currency":{"type":"string","description":"Shop currency (ISO 4217). All monetary values are in this currency, expressed in minor units."},"generatedAt":{"type":"string","format":"date-time","description":"When this report was generated (ISO 8601)."}},"required":["period","sales","ordersByStatus","ordersByPaymentStatus","carts","customers","fulfillment","catalog","topProducts","currency","generatedAt"]},"MerchantSalesTrendPointDto":{"type":"object","properties":{"date":{"type":"string","description":"Day in YYYY-MM-DD."},"revenue":{"type":"number","description":"Revenue in minor units for the day."},"orders":{"type":"number","description":"Revenue orders for the day."}},"required":["date","revenue","orders"]},"DiscountType":{"type":"string","enum":["PERCENTAGE","FIXED_AMOUNT","FREE_SHIPPING","BUY_X_GET_Y"]},"DiscountLifecycleStatus":{"type":"string","enum":["active","scheduled","expired","disabled"]},"MerchantDiscountOrderBy":{"type":"string","enum":["createdAt","updatedAt","endsAt","startsAt","usageCount","code","title"]},"DiscountTarget":{"type":"string","enum":["ORDER","LINE_ITEM","SHIPPING","COLLECTION","CATEGORY"]},"DiscountResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Discount ID"},"code":{"type":"string","description":"Discount code"},"title":{"type":"string","description":"Discount title"},"description":{"type":"string","description":"Description","nullable":true},"type":{"allOf":[{"$ref":"#/components/schemas/DiscountType"}]},"target":{"allOf":[{"$ref":"#/components/schemas/DiscountTarget"}]},"value":{"type":"number","description":"Discount value"},"currency":{"type":"string","description":"Currency code (ISO 4217)"},"currencyLocked":{"type":"boolean","description":"The currency can no longer be changed — the offer has been used or its personal codes were issued."},"usageLimit":{"type":"number","description":"Maximum total uses","nullable":true},"usageLimitPerCustomer":{"type":"number","description":"Maximum uses per customer","nullable":true},"usageCount":{"type":"number","description":"Current usage count"},"minimumOrderAmount":{"type":"number","description":"Minimum order amount","nullable":true},"maxDiscountAmount":{"type":"number","description":"Maximum discount amount in cents","nullable":true},"minimumQuantity":{"type":"number","description":"Minimum quantity","nullable":true},"startsAt":{"type":"string","description":"Start date","format":"date-time"},"endsAt":{"type":"string","description":"End date","format":"date-time","nullable":true},"appliesToAllProducts":{"type":"boolean","description":"Applies to all products"},"isActive":{"type":"boolean","description":"Is discount active"},"status":{"description":"Lifecycle status derived from the switch and the schedule (disabled wins over the dates). Computed server-side so the badge and the list filter can never disagree.","allOf":[{"$ref":"#/components/schemas/DiscountLifecycleStatus"}]},"requiresGrant":{"type":"boolean","description":"Grant-gated offer — the code requires a valid per-recipient grant at checkout"},"grantValidityDays":{"type":"number","description":"Personal-code validity in days from issuance (null = only the offer end date applies)","nullable":true},"isNewsletterCampaignReward":{"type":"boolean","description":"True when this offer is the reward of an ENABLED newsletter incentive campaign — its personal-code flag cannot be turned off and the offer cannot be deleted until the campaign is changed or disabled. Derived server-side, so clients do not join a second endpoint to learn it."},"createdAt":{"type":"string","description":"Created at","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at","format":"date-time"}},"required":["id","code","title","type","target","value","currency","usageCount","startsAt","appliesToAllProducts","isActive","status","requiresGrant","grantValidityDays","isNewsletterCampaignReward","createdAt","updatedAt"]},"DiscountListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DiscountResponseDto"}},"total":{"type":"number","description":"Total count"},"limit":{"type":"number","description":"Limit"},"offset":{"type":"number","description":"Offset"}},"required":["items","total","limit","offset"]},"CreateDiscountDto":{"type":"object","properties":{"code":{"type":"string","description":"Unique discount code. Optional for grant-gated offers (requiresGrant) — recipients receive personal codes, so the platform auto-generates an internal identifier when omitted.","maxLength":50},"title":{"type":"string","description":"Discount title","maxLength":255},"description":{"type":"string","description":"Description","maxLength":2000},"type":{"allOf":[{"$ref":"#/components/schemas/DiscountType"}]},"target":{"default":"ORDER","allOf":[{"$ref":"#/components/schemas/DiscountTarget"}]},"value":{"type":"number","description":"Discount value - percentage (0-100) or fixed amount in cents"},"currency":{"type":"string","description":"Currency code (ISO 4217), defaults to shop currency","example":"PLN"},"usageLimit":{"type":"number","description":"Maximum total uses (null = unlimited)"},"usageLimitPerCustomer":{"type":"number","description":"Maximum uses per customer"},"minimumOrderAmount":{"type":"number","description":"Minimum order amount in cents"},"maxDiscountAmount":{"type":"number","description":"Maximum discount amount in cents (cap for percentage discounts)"},"minimumQuantity":{"type":"number","description":"Minimum quantity of items in cart"},"startsAt":{"type":"string","description":"Start date (ISO 8601)"},"endsAt":{"type":"string","description":"End date (ISO 8601, null = no expiry)"},"appliesToAllProducts":{"type":"boolean","description":"Applies to all products","default":true},"productIds":{"description":"Specific product IDs to apply to","type":"array","items":{"type":"string"}},"collectionIds":{"description":"Specific collection IDs to apply to","type":"array","items":{"type":"string"}},"categoryIds":{"description":"Specific category IDs to apply to","type":"array","items":{"type":"string"}},"customerIds":{"description":"Specific customer IDs (exclusive discount)","type":"array","items":{"type":"string"}},"customerGroupIds":{"description":"Customer group IDs","type":"array","items":{"type":"string"}},"excludeSaleItems":{"type":"boolean","description":"Exclude items already on sale","default":false},"excludeProductIds":{"description":"Product IDs to exclude from discount","type":"array","items":{"type":"string"}},"excludeCategoryIds":{"description":"Category IDs to exclude from discount","type":"array","items":{"type":"string"}},"combinesWithProductDiscounts":{"type":"boolean","description":"Can combine with other product discounts","default":true},"combinesWithShippingDiscounts":{"type":"boolean","description":"Can combine with shipping discounts","default":true},"buyQuantity":{"type":"number","description":"Number of items to buy (X in Buy X Get Y)","example":2},"getQuantity":{"type":"number","description":"Number of items to get (Y in Buy X Get Y)","example":1},"getDiscountPercent":{"type":"number","description":"Discount percentage on \"get\" items (100 = free)","default":100},"isActive":{"type":"boolean","description":"Is discount active","default":true},"requiresGrant":{"type":"boolean","description":"Grant-gated offer: the code is not publicly usable — checkout requires a valid per-recipient grant issued by the platform (e.g. newsletter incentive)","default":false},"grantValidityDays":{"type":"number","description":"Personal-code validity in days from issuance (grant-gated offers; null = only the offer end date applies)","nullable":true,"minimum":1,"maximum":365}},"required":["title","type","value","startsAt"]},"UpdateDiscountDto":{"type":"object","properties":{"title":{"type":"string","description":"Discount title","maxLength":255},"description":{"type":"string","description":"Description","maxLength":2000},"value":{"type":"number","description":"Discount value"},"currency":{"type":"string","description":"Currency code (ISO 4217). Must be one of the currencies the store offers. Rejected once the offer has been used or its personal codes were issued.","example":"EUR"},"usageLimit":{"type":"number","description":"Maximum total uses (null clears the limit)","nullable":true},"usageLimitPerCustomer":{"type":"number","description":"Maximum uses per customer (null clears the limit)","nullable":true},"minimumOrderAmount":{"type":"number","description":"Minimum order amount in cents (null clears the requirement)","nullable":true},"maxDiscountAmount":{"type":"number","description":"Maximum discount amount in cents (cap for percentage discounts; null clears the cap)","nullable":true},"minimumQuantity":{"type":"number","description":"Minimum quantity of items (null clears the requirement)","nullable":true},"startsAt":{"type":"string","description":"Start date (ISO 8601)"},"endsAt":{"type":"string","description":"End date (ISO 8601; null clears the end date)","nullable":true},"appliesToAllProducts":{"type":"boolean","description":"Applies to all products"},"productIds":{"description":"Specific product IDs","type":"array","items":{"type":"string"}},"collectionIds":{"description":"Specific collection IDs","type":"array","items":{"type":"string"}},"categoryIds":{"description":"Specific category IDs","type":"array","items":{"type":"string"}},"customerIds":{"description":"Specific customer IDs","type":"array","items":{"type":"string"}},"customerGroupIds":{"description":"Specific customer group IDs","type":"array","items":{"type":"string"}},"combinesWithProductDiscounts":{"type":"boolean","description":"Combines with product discounts"},"combinesWithShippingDiscounts":{"type":"boolean","description":"Combines with shipping discounts"},"excludeSaleItems":{"type":"boolean","description":"Exclude sale items"},"excludeProductIds":{"description":"Excluded product IDs","type":"array","items":{"type":"string"}},"excludeCategoryIds":{"description":"Category IDs to exclude from discount","type":"array","items":{"type":"string"}},"buyQuantity":{"type":"number","description":"Number of items to buy (X in Buy X Get Y; null clears)","nullable":true},"getQuantity":{"type":"number","description":"Number of items to get (Y in Buy X Get Y; null clears)","nullable":true},"getDiscountPercent":{"type":"number","description":"Discount percentage on \"get\" items (100 = free; null clears)","nullable":true},"isActive":{"type":"boolean","description":"Is discount active"},"requiresGrant":{"type":"boolean","description":"Grant-gated offer: the code is not publicly usable — checkout requires a valid per-recipient grant issued by the platform (e.g. newsletter incentive)"},"grantValidityDays":{"type":"number","description":"Personal-code validity in days from issuance (grant-gated offers; null = only the offer end date applies)","nullable":true,"minimum":1,"maximum":365}}},"BlogCategoryResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Category ID"},"name":{"type":"string","description":"Category name"},"slug":{"type":"string","description":"URL-friendly slug"},"description":{"type":"string","description":"Category description","nullable":true},"image":{"type":"string","description":"Category image URL","nullable":true},"parentId":{"type":"string","description":"Parent category ID, or null for a root category","nullable":true},"level":{"type":"number","description":"Depth in the tree (0 = root)"},"path":{"type":"string","description":"Materialized path of slugs, e.g. \"poradniki/recenzje\"","nullable":true},"sortOrder":{"type":"number","description":"Sort order"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"postCount":{"type":"number","description":"Number of posts in category"},"createdAt":{"type":"string","description":"Creation date","format":"date-time"},"updatedAt":{"type":"string","description":"Last update date","format":"date-time"}},"required":["id","name","slug","level","sortOrder","postCount","createdAt","updatedAt"]},"CreateBlogCategoryDto":{"type":"object","properties":{"name":{"type":"string","description":"Category name","example":"News"},"slug":{"type":"string","description":"URL-friendly slug","example":"news"},"description":{"type":"string","description":"Category description"},"image":{"type":"string","description":"Category image URL"},"parentId":{"type":"string","description":"Parent category ID. Omit or null for a root category.","nullable":true},"sortOrder":{"type":"number","description":"Sort order","example":0},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"}},"required":["name","slug"]},"UpdateBlogCategoryDto":{"type":"object","properties":{"parentId":{"type":"string","description":"Parent category ID. Omit to keep it unchanged, null to move to root.","nullable":true},"name":{"type":"string","description":"Category name"},"slug":{"type":"string","description":"URL-friendly slug"},"description":{"type":"string","description":"Category description","nullable":true},"image":{"type":"string","description":"Category image URL","nullable":true},"sortOrder":{"type":"number","description":"Sort order"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true}}},"BlogTagResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Tag ID"},"name":{"type":"string","description":"Tag name"},"slug":{"type":"string","description":"URL-friendly slug"},"postCount":{"type":"number","description":"Number of posts with this tag"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"createdAt":{"type":"string","description":"Creation date","format":"date-time"}},"required":["id","name","slug","postCount","createdAt"]},"CreateBlogTagDto":{"type":"object","properties":{"name":{"type":"string","description":"Tag name","example":"Technology"},"slug":{"type":"string","description":"URL-friendly slug","example":"technology"},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"}},"required":["name","slug"]},"UpdateBlogTagDto":{"type":"object","properties":{"name":{"type":"string","description":"Tag name"},"slug":{"type":"string","description":"URL-friendly slug"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true}}},"BlogPostStatus":{"type":"string","enum":["DRAFT","PUBLISHED","SCHEDULED","ARCHIVED"]},"BlogCategoryMinimalDto":{"type":"object","properties":{"id":{"type":"string","description":"Category ID"},"name":{"type":"string","description":"Category name"},"slug":{"type":"string","description":"URL-friendly slug"}},"required":["id","name","slug"]},"BlogTagMinimalDto":{"type":"object","properties":{"id":{"type":"string","description":"Tag ID"},"name":{"type":"string","description":"Tag name"},"slug":{"type":"string","description":"URL-friendly slug"},"postCount":{"type":"number","description":"Number of posts with this tag"}},"required":["id","name","slug","postCount"]},"ProductSelectionResponseDto":{"type":"object","properties":{"productIds":{"description":"Product IDs pinned directly to the owner","type":"array","items":{"type":"string"}},"categoryIds":{"description":"Product category IDs included in the selection","type":"array","items":{"type":"string"}},"collectionIds":{"description":"Collection IDs included in the selection","type":"array","items":{"type":"string"}}},"required":["productIds","categoryIds","collectionIds"]},"BlogPostResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Post ID"},"title":{"type":"string","description":"Post title"},"slug":{"type":"string","description":"URL-friendly slug"},"excerpt":{"type":"string","description":"Short excerpt","nullable":true},"content":{"type":"string","description":"Full content"},"contentType":{"type":"string","description":"Content type"},"featuredImage":{"type":"string","description":"Featured image URL","nullable":true},"featuredImageAlt":{"type":"string","description":"Featured image alt text","nullable":true},"authorName":{"type":"string","description":"Author name","nullable":true},"authorBio":{"type":"string","description":"Author bio","nullable":true},"category":{"description":"Category the post belongs to (minimal: id, name, slug)","allOf":[{"$ref":"#/components/schemas/BlogCategoryMinimalDto"}]},"tags":{"description":"Tags attached to this post (minimal: id, name, slug, postCount)","type":"array","items":{"$ref":"#/components/schemas/BlogTagMinimalDto"}},"status":{"description":"Post status","allOf":[{"$ref":"#/components/schemas/BlogPostStatus"}]},"publishedAt":{"type":"string","description":"Publish date","format":"date-time","nullable":true},"viewCount":{"type":"number","description":"View count"},"commentCount":{"type":"number","description":"Comment count"},"allowComments":{"type":"boolean","description":"Allow comments"},"isFeatured":{"type":"boolean","description":"Featured post"},"metaTitle":{"type":"string","description":"SEO meta title","nullable":true},"metaDescription":{"type":"string","description":"SEO meta description","nullable":true},"productSelection":{"description":"Products pinned to this post (stored selection: direct product IDs, product category IDs, collection IDs). Read-only here — writes go through the product-selections endpoint. Empty arrays when nothing is pinned.","allOf":[{"$ref":"#/components/schemas/ProductSelectionResponseDto"}]},"createdAt":{"type":"string","description":"Creation date","format":"date-time"},"updatedAt":{"type":"string","description":"Last update date","format":"date-time"}},"required":["id","title","slug","content","contentType","tags","status","viewCount","commentCount","allowComments","isFeatured","productSelection","createdAt","updatedAt"]},"BlogPostsListResponseDto":{"type":"object","properties":{"items":{"description":"Blog posts on current page","type":"array","items":{"$ref":"#/components/schemas/BlogPostResponseDto"}},"total":{"type":"number","description":"Total number of posts matching the query"},"limit":{"type":"number","description":"Maximum items per page applied to this response"},"offset":{"type":"number","description":"Number of items skipped (offset-based pagination)"}},"required":["items","total","limit","offset"]},"CreateBlogPostDto":{"type":"object","properties":{"title":{"type":"string","description":"Post title","example":"Welcome to our blog"},"slug":{"type":"string","description":"URL-friendly slug","example":"welcome-to-our-blog"},"excerpt":{"type":"string","description":"Short excerpt/summary"},"content":{"type":"string","description":"Full HTML content"},"contentType":{"type":"string","description":"Content type (html or markdown)","default":"html"},"featuredImage":{"type":"string","description":"Featured image URL"},"featuredImageAlt":{"type":"string","description":"Featured image alt text"},"authorName":{"type":"string","description":"Author name"},"authorBio":{"type":"string","description":"Author bio"},"categoryId":{"type":"string","description":"Category ID"},"tagIds":{"description":"Tag IDs","maxItems":50,"type":"array","items":{"type":"string"}},"status":{"description":"Post status","default":"DRAFT","allOf":[{"$ref":"#/components/schemas/BlogPostStatus"}]},"publishedAt":{"type":"string","description":"Publish date (ISO 8601)"},"allowComments":{"type":"boolean","description":"Allow comments","default":true},"isFeatured":{"type":"boolean","description":"Featured post","default":false},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"}},"required":["title","slug","content"]},"UpdateBlogPostDto":{"type":"object","properties":{"title":{"type":"string","description":"Post title"},"slug":{"type":"string","description":"URL-friendly slug"},"excerpt":{"type":"string","description":"Short excerpt/summary"},"content":{"type":"string","description":"Full HTML content"},"contentType":{"type":"string","description":"Content type (html or markdown)"},"featuredImage":{"type":"string","description":"Featured image URL"},"featuredImageAlt":{"type":"string","description":"Featured image alt text"},"authorName":{"type":"string","description":"Author name"},"authorBio":{"type":"string","description":"Author bio"},"categoryId":{"type":"string","description":"Category ID"},"tagIds":{"description":"Tag IDs","maxItems":50,"type":"array","items":{"type":"string"}},"status":{"description":"Post status","allOf":[{"$ref":"#/components/schemas/BlogPostStatus"}]},"publishedAt":{"type":"string","description":"Publish date (ISO 8601)"},"allowComments":{"type":"boolean","description":"Allow comments"},"isFeatured":{"type":"boolean","description":"Featured post"},"metaTitle":{"type":"string","description":"SEO meta title"},"metaDescription":{"type":"string","description":"SEO meta description"}}},"ProductSelectionInputDto":{"type":"object","properties":{"productIds":{"description":"Product IDs pinned directly to the owner (each shown on the storefront strip)","type":"array","items":{"type":"string"}},"categoryIds":{"description":"Product category IDs — all products in these categories are included","type":"array","items":{"type":"string"}},"collectionIds":{"description":"Collection IDs — all products in these collections are included","type":"array","items":{"type":"string"}}},"required":["productIds","categoryIds","collectionIds"]},"BulkIdsDto":{"type":"object","properties":{"ids":{"description":"Entity IDs to act on","example":["uuid-1","uuid-2"],"type":"array","items":{"type":"string"}}},"required":["ids"]},"BulkActionFailureDto":{"type":"object","properties":{"id":{"type":"string","description":"ID of the entity that could not be processed"},"reason":{"type":"string","description":"Machine-readable reason code","enum":["NOT_FOUND","UNKNOWN_ERROR"]}},"required":["id","reason"]},"BulkActionResultDto":{"type":"object","properties":{"total":{"type":"number","description":"Total number of entities requested (equals ids.length)"},"successful":{"type":"number","description":"Count of entities that completed successfully"},"failed":{"description":"Per-id failures with stable reason codes","type":"array","items":{"$ref":"#/components/schemas/BulkActionFailureDto"}}},"required":["total","successful","failed"]},"CreateAttributeOptionDto":{"type":"object","properties":{"value":{"type":"string","description":"Option value (internal)","maxLength":255},"label":{"type":"string","description":"Option label (display)","maxLength":255},"sortOrder":{"type":"number","description":"Sort order","default":0},"colorHex":{"type":"string","description":"Color hex value (for COLOR type)","maxLength":7},"surchargeAmount":{"type":"number","description":"Surcharge amount when this option is selected. NULL = no surcharge. Unit depends on surchargeType: FIXED = grosze (minor units); PERCENT = thousandths of percent (1000 = 10.00%)","minimum":0},"surchargeType":{"description":"Surcharge calculation type","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Default option marker — at most 1 per definition","default":false},"linkedVariantId":{"type":"string","description":"Link to ProductVariant so picking this option sells that variant (stock is decremented at checkout when the variant tracks inventory; an untracked component — a service or digital item — simply has no counter). The variant must exist and not be withdrawn. Parent definition must have fillingMode IN (CUSTOMER, BOTH) AND type IN (SELECT, RADIO, CHECKBOX).","format":"uuid"}},"required":["value","label"]},"MerchantCreateConfiguratorFieldDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug (auto-generated if not provided)","maxLength":255},"type":{"description":"Attribute type","allOf":[{"$ref":"#/components/schemas/AttributeType"}]},"description":{"type":"string","description":"Attribute description"},"defaultValue":{"type":"object","description":"Default value (JSON)","additionalProperties":true},"isVisible":{"type":"boolean","description":"Is visible on product page","default":true},"isFilterable":{"type":"boolean","description":"Can be used for filtering","default":false},"isRequired":{"type":"boolean","description":"Is required for products","default":false},"isLocalized":{"type":"boolean","description":"Supports localization","default":false},"displayOrder":{"type":"number","description":"Display order","default":0},"minValue":{"type":"number","description":"Minimum value (for NUMBER type)"},"maxValue":{"type":"number","description":"Maximum value (for NUMBER type)"},"billingMode":{"description":"How surcharge affects pricing. Omit/null = informational only (no price effect). BUNDLED = surcharge in unitPrice. SEPARATE_LINE = separate OrderItem.","allOf":[{"$ref":"#/components/schemas/AttributeBillingMode"}]},"taxClassId":{"type":"string","description":"Tax class for surcharge. Omit/null = inherit from variant.taxClassId.","format":"uuid"},"namespace":{"type":"string","description":"Optional grouping namespace (e.g. \"inventory\", \"marketing\", \"content\"). NULL = ungrouped.","maxLength":64,"nullable":true},"options":{"description":"Predefined options (for SELECT/CHECKBOX/RADIO)","type":"array","items":{"$ref":"#/components/schemas/CreateAttributeOptionDto"}},"showIfConditions":{"description":"Visibility conditions (AND). The field shows only when every rule is met; used to model sub-components installable only with a specific parent option.","type":"array","items":{"$ref":"#/components/schemas/AttributeVisibilityConditionDto"}},"fillingMode":{"type":"string","description":"Who answers the field: CUSTOMER (buyer picks it in the product configurator) or BOTH (merchant may pre-fill a value the buyer can change). Defaults to CUSTOMER. MERCHANT-filled metadata attributes are managed through the separate /merchant/v1/attributes resource.","enum":["CUSTOMER","BOTH"],"default":"CUSTOMER"}},"required":["name","type"]},"AttributeOptionSyncDto":{"type":"object","properties":{"id":{"type":"string","description":"Option ID (for existing options)"},"value":{"type":"string","description":"Option value (internal)","maxLength":255},"label":{"type":"string","description":"Option label (display)","maxLength":255},"sortOrder":{"type":"number","description":"Sort order","default":0},"colorHex":{"type":"string","description":"Color hex value (for COLOR type)","maxLength":7},"surchargeAmount":{"type":"number","description":"Surcharge amount; null = no surcharge","minimum":0,"nullable":true},"surchargeType":{"description":"Surcharge type","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Default option marker"},"linkedVariantId":{"type":"string","format":"uuid","description":"Linked ProductVariant for stock decrement","nullable":true}},"required":["value","label"]},"MerchantUpdateConfiguratorFieldDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute name","maxLength":255},"slug":{"type":"string","description":"URL-friendly slug","maxLength":255},"description":{"type":"string","description":"Attribute description"},"defaultValue":{"type":"object","description":"Default value (JSON)","additionalProperties":true},"isVisible":{"type":"boolean","description":"Is visible on product page"},"isFilterable":{"type":"boolean","description":"Can be used for filtering"},"isRequired":{"type":"boolean","description":"Is required for products"},"isLocalized":{"type":"boolean","description":"Supports localization"},"displayOrder":{"type":"number","description":"Display order"},"minValue":{"type":"number","description":"Minimum value (for NUMBER type)"},"maxValue":{"type":"number","description":"Maximum value (for NUMBER type)"},"billingMode":{"description":"Billing mode; null = no price effect","allOf":[{"$ref":"#/components/schemas/AttributeBillingMode"}]},"taxClassId":{"type":"string","description":"Tax class ID; null = inherit from variant","format":"uuid","nullable":true},"namespace":{"type":"string","description":"Optional grouping namespace (e.g. \"inventory\"). NULL = ungrouped.","maxLength":64,"nullable":true},"options":{"description":"Options to sync (for SELECT/CHECKBOX/RADIO) - replaces all existing options","type":"array","items":{"$ref":"#/components/schemas/AttributeOptionSyncDto"}},"showIfConditions":{"description":"Visibility conditions (AND), replaces the stored list. Empty array clears (field always visible); omit to preserve.","nullable":true,"type":"array","items":{"$ref":"#/components/schemas/AttributeVisibilityConditionDto"}},"fillingMode":{"type":"string","description":"Who answers the field: CUSTOMER or BOTH. A configurator field cannot be demoted to a MERCHANT-filled metadata attribute through this resource.","enum":["CUSTOMER","BOTH"]}}},"AttributeOptionDetailResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Option ID"},"attributeDefinitionId":{"type":"string","format":"uuid","description":"Parent attribute definition ID"},"value":{"type":"string","description":"Option value (internal identifier, unique per definition)"},"label":{"type":"string","description":"Option label (displayed to the customer)"},"sortOrder":{"type":"number","description":"Sort order"},"colorHex":{"type":"string","nullable":true,"description":"Hex color value (for COLOR type options)"},"surchargeAmount":{"type":"number","nullable":true,"description":"Surcharge when this option is selected. NULL = no surcharge. Unit depends on surchargeType: FIXED = minor currency units; PERCENT = thousandths of percent (1000 = 10.00%)."},"surchargeType":{"nullable":true,"description":"Surcharge calculation type.","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Whether this option is pre-selected by default."},"linkedVariantId":{"type":"string","format":"uuid","nullable":true,"description":"Linked ProductVariant sold as a component when this option is selected, priced from that variant. Stock is decremented only when the variant tracks inventory — a service or digital component simply has no counter. NULL = no linked component."},"createdAt":{"type":"string","format":"date-time","description":"Created at timestamp"},"updatedAt":{"type":"string","format":"date-time","description":"Updated at timestamp"}},"required":["id","attributeDefinitionId","value","label","sortOrder","isDefault","createdAt","updatedAt"]},"UpdateAttributeOptionDto":{"type":"object","properties":{"value":{"type":"string","description":"Option value (internal)","maxLength":255},"label":{"type":"string","description":"Option label (display)","maxLength":255},"sortOrder":{"type":"number","description":"Sort order"},"colorHex":{"type":"string","description":"Color hex value (for COLOR type)","maxLength":7},"surchargeAmount":{"type":"number","description":"Surcharge amount; null clears, omit preserves","minimum":0,"nullable":true},"surchargeType":{"description":"Surcharge type","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Default option marker"},"linkedVariantId":{"type":"string","description":"Linked ProductVariant for stock decrement; null unlinks","format":"uuid","nullable":true}}},"AttributeSetResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Attribute set ID"},"name":{"type":"string","description":"Attribute set name"},"description":{"type":"string","description":"Attribute set description","nullable":true},"attributes":{"description":"Attributes in this set","type":"array","items":{"$ref":"#/components/schemas/AttributeDefinitionResponseDto"}},"categoryCount":{"type":"number","description":"Number of categories using this set"},"createdAt":{"type":"string","description":"Created at timestamp","format":"date-time"},"updatedAt":{"type":"string","description":"Updated at timestamp","format":"date-time"}},"required":["id","name","attributes","categoryCount","createdAt","updatedAt"]},"CreateAttributeSetDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute set name","maxLength":255},"description":{"type":"string","description":"Attribute set description"},"attributeIds":{"description":"Attribute definition IDs to include","type":"array","items":{"type":"string"}}},"required":["name"]},"UpdateAttributeSetDto":{"type":"object","properties":{"name":{"type":"string","description":"Attribute set name","maxLength":255},"description":{"type":"string","description":"Attribute set description"},"attributeIds":{"description":"Attribute definition IDs to include","type":"array","items":{"type":"string"}}}},"ProductWithConfiguratorDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Product ID."},"name":{"type":"string","description":"Product name."},"slug":{"type":"string","description":"URL-friendly product slug."},"scopedDefinitionCount":{"type":"number","description":"Number of per-product scoped AttributeDefinitions on this product.","example":3},"attributeSetId":{"type":"string","format":"uuid","nullable":true,"description":"Shared AttributeSet ID assigned to this product. NULL = no shared set."},"attributeSetName":{"type":"string","nullable":true,"description":"Name of the assigned AttributeSet. NULL when no set is assigned."}},"required":["id","name","slug","scopedDefinitionCount"]},"ConfiguratorLinkedVariantAdminDto":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","description":"Linked variant ID."},"productId":{"type":"string","format":"uuid","description":"Owning product ID."},"productName":{"type":"string","description":"Owning product name (component label)."},"variantName":{"type":"string","description":"Variant name (e.g. \"Default\", \"Small / Red\")."},"sku":{"type":"string","nullable":true,"description":"Variant SKU."},"price":{"type":"number","description":"Current variant price in minor units (component charge basis)."},"quantityAvailable":{"type":"number","description":"Sellable quantity — on hand minus reservations and safety stock, clamped at 0. Meaningless when trackQuantity is false."},"isAvailable":{"type":"boolean","description":"Whether currently purchasable — true when inventory is not tracked, when stock is left, or when backorders are allowed."},"trackQuantity":{"type":"boolean","description":"Whether inventory is tracked for this variant."}},"required":["variantId","productId","productName","variantName","price","quantityAvailable","isAvailable","trackQuantity"]},"ProductConfiguratorOptionAdminDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Option ID (goes into cart attributeSelections)."},"value":{"type":"string","description":"Machine value (slug-style)."},"label":{"type":"string","description":"Display label."},"colorHex":{"type":"string","nullable":true,"description":"Hex colour for swatch rendering (COLOR fields)."},"isDefault":{"type":"boolean","description":"Whether pre-selected by default."},"surchargeAmount":{"type":"number","nullable":true,"description":"Surcharge per unit after per-product override resolution (minor units for FIXED). Null for linked components — their charge is the variant price."},"surchargeType":{"nullable":true,"description":"How to interpret surchargeAmount — FIXED or PERCENT.","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"linkedVariantId":{"type":"string","format":"uuid","nullable":true,"description":"Resolved linked variant ID (per-product overrides applied). Set = this choice is a stocked component; when `linkedVariant` is null despite this being set, the variant was withdrawn and the choice is unbuyable."},"linkedVariant":{"nullable":true,"description":"Stocked component behind this choice (after per-product override resolution). Null when the option is a plain surcharge, or when the linked variant no longer exists (see linkedVariantId).","type":"object","allOf":[{"$ref":"#/components/schemas/ConfiguratorLinkedVariantAdminDto"}]}},"required":["id","value","label","isDefault"]},"ProductConfiguratorConditionAdminDto":{"type":"object","properties":{"fieldId":{"type":"string","format":"uuid","description":"The configurator field whose answer controls visibility (parent field)."},"operator":{"type":"string","enum":["EQUALS","NOT_EQUALS","ONE_OF"],"description":"EQUALS/ONE_OF with optionIds: visible when ANY listed option is selected. NOT_EQUALS: visible when NONE is selected."},"optionIds":{"nullable":true,"description":"Option ids of the referenced field.","type":"array","items":{"type":"string"}},"value":{"type":"string","nullable":true,"description":"Answer to compare against for free-input parents."}},"required":["fieldId","operator"]},"ProductConfiguratorFieldAdminDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Attribute definition ID (goes into cart attributeSelections)."},"name":{"type":"string","description":"Field name shown to the shopper."},"description":{"type":"string","nullable":true,"description":"Optional field description."},"type":{"description":"Input type (SELECT / RADIO / CHECKBOX / TEXT / TEXTAREA / NUMBER / DATE / ...).","allOf":[{"$ref":"#/components/schemas/AttributeType"}]},"fillingMode":{"description":"Who fills the value (CUSTOMER or BOTH for configurator fields).","allOf":[{"$ref":"#/components/schemas/AttributeFillingMode"}]},"billingMode":{"nullable":true,"description":"Surcharge billing mode. NULL = informational only.","allOf":[{"$ref":"#/components/schemas/AttributeBillingMode"}]},"isRequired":{"type":"boolean","description":"Whether an answer is required to add the product to the cart."},"sortOrder":{"type":"number","description":"Render order (set fields first, then product-own fields)."},"minValue":{"type":"number","nullable":true,"description":"Min value / min length constraint."},"maxValue":{"type":"number","nullable":true,"description":"Max value / max length constraint."},"options":{"description":"Selectable choices (empty for text-like fields).","type":"array","items":{"$ref":"#/components/schemas/ProductConfiguratorOptionAdminDto"}},"visibleIf":{"nullable":true,"description":"Visibility rules (AND). Null = always visible. Render the field only when every rule is met against the current selections; clear its value when it becomes hidden (the server rejects hidden-field selections).","type":"array","items":{"$ref":"#/components/schemas/ProductConfiguratorConditionAdminDto"}}},"required":["id","name","type","fillingMode","isRequired","sortOrder","options"]},"ScopedAttributeOptionDto":{"type":"object","properties":{"id":{"type":"string","description":"Option ID."},"value":{"type":"string","description":"Option internal value."},"label":{"type":"string","description":"Option display label."},"sortOrder":{"type":"number","description":"Sort order for display."},"colorHex":{"type":"string","nullable":true,"description":"Hex color value for COLOR type options."},"surchargeAmount":{"type":"number","nullable":true,"description":"Surcharge amount in minor units (grosze for FIXED, thousandths of percent for PERCENT). NULL = no surcharge.","example":1500},"surchargeType":{"nullable":true,"description":"Surcharge calculation type.","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isDefault":{"type":"boolean","description":"Whether this is the default option."},"linkedVariantId":{"type":"string","nullable":true,"format":"uuid","description":"Linked ProductVariant ID for atomic stock decrement at checkout."}},"required":["id","value","label","sortOrder","isDefault"]},"ScopedAttributeDefinitionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Scoped attribute definition ID."},"scopeProductId":{"type":"string","format":"uuid","description":"Product ID this definition is scoped to."},"name":{"type":"string","description":"Attribute name."},"slug":{"type":"string","description":"URL-friendly slug."},"type":{"description":"Attribute type (immutable after creation).","allOf":[{"$ref":"#/components/schemas/AttributeType"}]},"description":{"type":"string","nullable":true,"description":"Optional attribute description."},"fillingMode":{"description":"Who fills the value: MERCHANT (admin), CUSTOMER (in cart), or BOTH.","allOf":[{"$ref":"#/components/schemas/AttributeFillingMode"}]},"billingMode":{"nullable":true,"description":"Surcharge billing mode. NULL = informational only, no price effect.","allOf":[{"$ref":"#/components/schemas/AttributeBillingMode"}]},"taxClassId":{"type":"string","format":"uuid","nullable":true,"description":"Tax class ID for surcharge. NULL = inherit from variant."},"isRequired":{"type":"boolean","description":"Whether the attribute is required."},"isVisible":{"type":"boolean","description":"Whether the attribute is visible on the product page."},"displayOrder":{"type":"number","description":"Display order for UI rendering."},"minValue":{"type":"number","nullable":true,"description":"Minimum numeric value constraint."},"maxValue":{"type":"number","nullable":true,"description":"Maximum numeric value constraint."},"options":{"description":"Options for SELECT / CHECKBOX / RADIO types.","type":"array","items":{"$ref":"#/components/schemas/ScopedAttributeOptionDto"}},"showIfConditions":{"description":"Visibility conditions (AND) — the field shows only when every rule is met; models sub-components installable only with a specific parent option. NULL = always visible.","nullable":true,"type":"array","items":{"$ref":"#/components/schemas/AttributeVisibilityConditionDto"}},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 creation timestamp."},"updatedAt":{"type":"string","format":"date-time","description":"ISO 8601 last-update timestamp."}},"required":["id","scopeProductId","name","slug","type","fillingMode","isRequired","isVisible","displayOrder","options","createdAt","updatedAt"]},"ProductAttributeOptionOverrideResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Override ID"},"productId":{"type":"string","format":"uuid","description":"Product ID"},"optionId":{"type":"string","format":"uuid","description":"Attribute option ID"},"linkedVariantId":{"type":"string","format":"uuid","nullable":true,"description":"Linked variant ID (for BUNDLE_ONLY visibility)"},"linkedVariantExplicit":{"type":"boolean","description":"Tri-state flag — see service docs"},"surchargeAmount":{"type":"number","nullable":true,"description":"Surcharge amount in minor units"},"surchargeType":{"nullable":true,"description":"Surcharge type","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isHidden":{"type":"boolean","description":"Whether the option is hidden"},"createdBy":{"type":"string","format":"uuid","nullable":true,"description":"User ID who created this override"},"updatedBy":{"type":"string","format":"uuid","nullable":true,"description":"User ID who last updated this override"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","productId","optionId","linkedVariantExplicit","isHidden","createdAt","updatedAt"]},"UpsertProductAttributeOverrideDto":{"type":"object","properties":{"linkedVariantId":{"type":"string","description":"Override linked variant. Meaning depends on linkedVariantExplicit flag (tri-state).","format":"uuid","nullable":true},"linkedVariantExplicit":{"type":"boolean","description":"Tri-state flag: false (default) = inherit from AttributeOption; true = use linkedVariantId literally (incl. NULL = \"explicitly detached\")"},"surchargeAmount":{"type":"number","description":"Override surcharge amount in minor units (NULL = inherit). Auto-cleared if linkedVariantId set.","minimum":0},"surchargeType":{"description":"Override surcharge type (NULL = inherit).","allOf":[{"$ref":"#/components/schemas/AttributeOptionSurchargeType"}]},"isHidden":{"type":"boolean","description":"Hide this option for this product (default false).","default":false}}},"ProductDisabledAttributeResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"productId":{"type":"string","format":"uuid"},"definitionId":{"type":"string","format":"uuid"},"createdBy":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","productId","definitionId","createdAt"]},"MerchantDisableConfiguratorFieldDto":{"type":"object","properties":{"fieldId":{"type":"string","description":"ID of the configurator field (attribute definition) to hide on this product.","format":"uuid"}},"required":["fieldId"]},"DuplicateConfiguratorResultDto":{"type":"object","properties":{"duplicated":{"type":"number","description":"Number of scoped AttributeDefinitions (+ their options) successfully duplicated to the target product.","example":3},"skipped":{"type":"number","description":"Number of scoped definitions skipped due to slug conflict with an existing definition on the target product.","example":1},"attributeSetCopied":{"type":"boolean","description":"Whether the AttributeSet binding was copied from source to target (only when target had no set and source had one).","example":true}},"required":["duplicated","skipped","attributeSetCopied"]}}}}