{"openapi":"3.0.0","paths":{"/auth/login":{"post":{"description":"Authenticate user with email and password","operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponseDto"}}}}},"summary":"User login","tags":["Auth Controller"]}},"/auth/refresh":{"post":{"description":"Generate new access and refresh tokens using a valid refresh token","operationId":"AuthController_refresh","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"200":{"description":"Token refreshed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponseDto"}}}}},"summary":"Refresh access token","tags":["Auth Controller"]}},"/auth/profile":{"get":{"description":"Returns the logged-in user profile using userId from JWT","operationId":"AuthController_getProfile","parameters":[],"responses":{"200":{"description":"User profile retrieved successfully"}},"security":[{"access-token":[]}],"summary":"Get current user profile","tags":["Auth Controller"]}},"/countries":{"post":{"description":"Create a new country with currency details","operationId":"CountryController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCountryDto"}}}},"responses":{"201":{"description":"Country created successfully"}},"security":[{"access-token":[]}],"summary":"Create a new country","tags":["Country Controller"]},"get":{"description":"Retrieve countries with optional filters for active status and search","operationId":"CountryController_findAll","parameters":[{"name":"isActive","required":false,"in":"query","description":"Filter by active status","schema":{"example":true,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search by country name or currency code","schema":{"example":"United","type":"string"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Countries retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CountryResponseDto"}}}}}},"security":[{"access-token":[]}],"summary":"Get countries with filters","tags":["Country Controller"]}},"/countries/{id}":{"get":{"description":"Retrieve a specific country by its ID","operationId":"CountryController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Country retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get country by ID","tags":["Country Controller"]},"patch":{"description":"Update a country by its ID","operationId":"CountryController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCountryDto"}}}},"responses":{"200":{"description":"Country updated successfully"}},"security":[{"access-token":[]}],"summary":"Update country","tags":["Country Controller"]}},"/states":{"post":{"description":"Create a new state for a country","operationId":"StateController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateStateDto"}}}},"responses":{"201":{"description":"State created successfully"}},"security":[{"access-token":[]}],"summary":"Create a new state","tags":["State Controller"]},"get":{"description":"Retrieve states with optional filters for country, active status, and search","operationId":"StateController_findAll","parameters":[{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"example":1,"type":"number"}},{"name":"isActive","required":false,"in":"query","description":"Filter by active status","schema":{"example":true,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search by state name","schema":{"example":"California","type":"string"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"States retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StateResponseDto"}}}}}},"security":[{"access-token":[]}],"summary":"Get states with filters","tags":["State Controller"]}},"/states/{id}":{"get":{"description":"Retrieve a specific state by its ID","operationId":"StateController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"State retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get state by ID","tags":["State Controller"]},"patch":{"description":"Update a state by its ID","operationId":"StateController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStateDto"}}}},"responses":{"200":{"description":"State updated successfully"}},"security":[{"access-token":[]}],"summary":"Update state","tags":["State Controller"]}},"/products/search":{"get":{"description":"Open API to retrieve product list by country or state name. If state is provided, filtering is done by state only and country is not required. If state is not provided, country is required. Pagination (page, size) is required.","operationId":"ProductController_getOpenProducts","parameters":[{"name":"country","required":false,"in":"query","description":"Country name. Required when state is not provided. Example: \"United States\"","schema":{"example":"United States","type":"string"}},{"name":"state","required":false,"in":"query","description":"State name. If provided, filtering will be done by state only and country is not required. Example: \"California\"","schema":{"example":"California","type":"string"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination. Starting from 0","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page. maximum 100","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Products retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenProductListResponseDto"}}}}},"summary":"Get public product list by country/state","tags":["Product Controller"]}},"/products":{"post":{"description":"Create product with country specific prices.","operationId":"ProductController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateProductDto"}}}},"responses":{"201":{"description":"Product created successfully"}},"security":[{"access-token":[]}],"summary":"Create product","tags":["Product Controller"]},"get":{"description":"Retrieve products with optional search by product name, country name, or state name. Latest products appear first. Returns basic product info without country prices.","operationId":"ProductController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by product name, country name, or state name","schema":{"example":"Product","type":"string"}},{"name":"isFastTrack","required":false,"in":"query","description":"Filter products by fast track flag","schema":{"example":true,"type":"boolean"}},{"name":"isPaperCopy","required":false,"in":"query","description":"Filter products by paper copy flag","schema":{"example":false,"type":"boolean"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Products retrieved successfully"}},"security":[{"access-token":[]}],"summary":"Get products with filters","tags":["Product Controller"]}},"/products/like-search":{"get":{"description":"Retrieve products using LIKE-based search on product name, country name, and state name. Existing product list API remains unchanged.","operationId":"ProductController_findAllWithLikeSearch","parameters":[{"name":"search","required":false,"in":"query","description":"Search by product name, country name, or state name","schema":{"example":"Prod","type":"string"}},{"name":"isFastTrack","required":false,"in":"query","description":"Filter products by fast track flag","schema":{"example":true,"type":"boolean"}},{"name":"isPaperCopy","required":false,"in":"query","description":"Filter products by paper copy flag","schema":{"example":false,"type":"boolean"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Products retrieved successfully"}},"security":[{"access-token":[]}],"summary":"Get products with LIKE search","tags":["Product Controller"]}},"/products/{id}":{"get":{"description":"Get product by ID","operationId":"ProductController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get product by ID","tags":["Product Controller"]},"patch":{"description":"Update product","operationId":"ProductController_update","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateProductDto"}}}},"responses":{"200":{"description":"Product updated successfully"}},"security":[{"access-token":[]}],"summary":"Update product","tags":["Product Controller"]},"delete":{"description":"Delete product","operationId":"ProductController_delete","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":"Product deleted successfully"}},"security":[{"access-token":[]}],"summary":"Delete product","tags":["Product Controller"]}},"/orders":{"post":{"description":"Create a new order with all order details.","operationId":"OrderController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateOrderDto"}}}},"responses":{"201":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateUpdateResponseDto"}}}}},"summary":"Create order","tags":["Order Controller"]},"get":{"description":"Retrieve orders with optional search by order ID, title number, customer email, application number, instrument copy number, billing email, post code, address, city, or manually added order notes. Filter by status, customer ID, UTM source, payment method, date range. Latest orders appear first.","operationId":"OrderController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by order ID, title number, customer email, application number, instrument copy number, billing email, post code, address, city, or manually added order notes","schema":{"type":"string"}},{"name":"orderStatusId","required":false,"in":"query","description":"Filter by one or more order status IDs (supports comma-separated or repeated query params)","schema":{"example":[1,2],"type":"array","items":{"type":"number"}}},{"name":"customerId","required":false,"in":"query","description":"Filter by customer ID","schema":{"type":"number"}},{"name":"customerEmail","required":false,"in":"query","description":"Filter by customer email","schema":{"type":"string"}},{"name":"postCode","required":false,"in":"query","description":"Filter by post code","schema":{"type":"string"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"type":"number"}},{"name":"stateId","required":false,"in":"query","description":"Filter by state ID","schema":{"type":"number"}},{"name":"isExpressDelivery","required":false,"in":"query","description":"Filter by express delivery status","schema":{"type":"boolean"}},{"name":"isRequestedPaperCopy","required":false,"in":"query","description":"Filter by paper copy requested","schema":{"type":"boolean"}},{"name":"paymentMethod","required":false,"in":"query","description":"Filter by payment method","schema":{"type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Filter by UTM source (exact match). Use \"notSet\" for orders with no UTM source.","schema":{"example":"google","type":"string"}},{"name":"orderStatus","required":false,"in":"query","description":"Filter by order status (can be comma-separated)","schema":{"type":"array","items":{"type":"string"}}},{"name":"isCertified","required":false,"in":"query","description":"Filter by certified orders (only orders with physical products)","schema":{"type":"boolean"}},{"name":"hasInstrumentCopy","required":false,"in":"query","description":"Filter orders containing Instrument Copy product","schema":{"type":"boolean"}},{"name":"hasLimReport","required":false,"in":"query","description":"Filter orders containing LIM Report product","schema":{"type":"boolean"}},{"name":"isAbandonmentRecovered","required":false,"in":"query","description":"Filter orders recovered after an abandonment email was sent.","schema":{"type":"boolean"}},{"name":"upSellSource","required":false,"in":"query","description":"Filter by upsell source. ALL = any order with an upsell source set.","schema":{"enum":["ORDER","EMAIL","ADMIN","ALL"],"type":"string"}},{"name":"upSellEntryChannel","required":false,"in":"query","description":"Filter by tracking-entry channel for Document Link upsells (e.g. DOCUMENT_REMINDER_EMAIL)","schema":{"type":"string","enum":["PAYMENT_SUCCESS","DOCUMENT_DELIVERY_EMAIL","DOCUMENT_REMINDER_EMAIL","ORDER_CONFIRMATION_EMAIL","TRANSIT_EMAIL","ADMIN_PANEL","TRACKING_DIRECT","UNKNOWN"]}},{"name":"fromDate","required":false,"in":"query","description":"Filter orders created from this date (ISO 8601 format)","schema":{"type":"string"}},{"name":"toDate","required":false,"in":"query","description":"Filter orders created until this date (ISO 8601 format)","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"type":"string","enum":["createdAt","updatedAt","totalAmount","customerEmail","postCode","titleNumber"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllOrdersResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get orders with filters for admin","tags":["Order Controller"]}},"/orders/upsell":{"post":{"description":"Allows customers to purchase recommended products. Fetches details from parent order. No authentication required.","operationId":"OrderController_createUpSellOrder","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpSellOrderDto"}}}},"responses":{"201":{"description":"UpSell order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateUpdateResponseDto"}}}}},"summary":"Create customer upSell order","tags":["Order Controller"]}},"/orders/history":{"get":{"description":"Retrieves all orders for a specific customer email address including total count with pagination support","operationId":"OrderController_getOrderHistoryByEmail","parameters":[{"name":"customerEmail","required":false,"in":"query","description":"Customer email (Required if postCode is not provided)","schema":{"example":"customer@example.com","type":"string"}},{"name":"postCode","required":false,"in":"query","description":"Post Code (Required if customerEmail is not provided)","schema":{"example":"SW1A 1AA","type":"string"}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Order history retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderHistoryResponseDto"}}}},"400":{"description":"Invalid email provided"},"404":{"description":"No orders found for this email"}},"security":[{"access-token":[]}],"summary":"Get order history by customer email","tags":["Order Controller"]}},"/orders/payment-methods":{"get":{"operationId":"OrderController_getPaymentMethods","parameters":[],"responses":{"200":{"description":"Payment methods retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"access-token":[]}],"summary":"Get available payment methods","tags":["Order Controller"]}},"/orders/utm-sources":{"get":{"operationId":"OrderController_getUtmSources","parameters":[],"responses":{"200":{"description":"UTM sources retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"access-token":[]}],"summary":"Get distinct UTM sources","tags":["Order Controller"]}},"/orders/up-sell-sources":{"get":{"operationId":"OrderController_getUpSellSources","parameters":[],"responses":{"200":{"description":"Upsell sources retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"access-token":[]}],"summary":"Get distinct upsell sources","tags":["Order Controller"]}},"/orders/{id}/dispute-logs":{"get":{"description":"Download customer activity logs and payment history with full raw metadata/payloads as a plain text file. Intended for legal/dispute resolution. Only customer-initiated actions are included.","operationId":"OrderController_downloadDisputeLogs","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Dispute logs text file downloaded successfully"},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Download order dispute logs (raw text)","tags":["Order Controller"]}},"/orders/update-email":{"patch":{"description":"Update the email address for an order. If a customer with the new email exists, the order will be linked to that customer. Otherwise, the current customer's email will be updated.","operationId":"OrderController_updateOrderEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderEmailDto"}}}},"responses":{"200":{"description":"Order email updated successfully"},"400":{"description":"Invalid email format or missing required fields"},"404":{"description":"Order not found"}},"summary":"Update order email","tags":["Order Controller"]}},"/orders/{id}":{"get":{"description":"Get complete order details by ID. When called with a valid Bearer token, also returns draftEmailAttachments.","operationId":"OrderController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDetailsResponseDto"}}}}},"summary":"Get order by ID","tags":["Order Controller"]},"patch":{"description":"Update order status and order date","operationId":"OrderController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderDto"}}}},"responses":{"200":{"description":"Order updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateUpdateResponseDto"}}}},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Update order for admin","tags":["Order Controller"]}},"/orders/activity-logs/{id}":{"get":{"description":"Retrieve all activity logs for a specific order.","operationId":"OrderController_findOrderActivityLogs","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Activity logs retrieved successfully, grouped by performer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderActivityLogsByPerformerResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get order activity logs by order ID","tags":["Order Controller"]}},"/orders/update/{id}":{"patch":{"description":"Open API to update order with all order details. Uses CreateUpdateOrderDto to update all fields including products, customer, address, shipping, and UTM tracking.","operationId":"OrderController_updateOpen","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateOrderDto"}}}},"responses":{"200":{"description":"Order updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateUpdateResponseDto"}}}},"404":{"description":"Order not found"}},"summary":"Update order (Open API)","tags":["Order Controller"]}},"/orders/bulk-status-update":{"patch":{"description":"Update the same status for multiple orders in a single request.","operationId":"OrderController_updateMultipleOrderStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMultipleOrderStatusDto"}}}},"responses":{"200":{"description":"Multiple order statuses updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMultipleOrderStatusResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Update multiple orders status","tags":["Order Controller"]}},"/orders/shipping-address/{id}":{"patch":{"description":"Updates shipping recipient name, phone, and address fields. Only include fields you want to change; at least one field is required.","operationId":"OrderController_updateOrderShippingAddress","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrderShippingAddressDto"}}}},"responses":{"200":{"description":"Shipping address updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateUpdateResponseDto"}}}},"400":{"description":"No shipping fields supplied or invalid payload"},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Update order shipping address","tags":["Order Controller"]}},"/orders/extend-link-validity/{id}":{"post":{"description":"Extend the document download link validity for a specific order. The customer keeps using the same tracking link until the new expiry date.","operationId":"OrderController_extendDocumentLinkValidity","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendDocumentLinkValidityDto"}}}},"responses":{"200":{"description":"Document link validity extended successfully"},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Extend document link validity","tags":["Order Controller"]}},"/orders/refund/{id}":{"post":{"description":"Process refund for an order with refund reason","operationId":"OrderController_refundOrder","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundOrderDto"}}}},"responses":{"200":{"description":"Order refunded successfully"},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Refund order","tags":["Order Controller"]}},"/orders/note/{id}":{"post":{"description":"Add a note to an order. The note will be saved in activity log.","operationId":"OrderController_addOrderNote","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOrderNoteDto"}}}},"responses":{"200":{"description":"Note added successfully"},"404":{"description":"Order not found"}},"security":[{"access-token":[]}],"summary":"Add note to order","tags":["Order Controller"]}},"/orders/send-email/{id}":{"post":{"description":"Send order email using subject/body and any draft attachments previously staged via POST /orders/draft-attachments/:id. Draft attachments are merged automatically and cleared after a successful send. Optional applicationNumber: omit to leave unchanged, null to clear; non-empty values require a certified order (isCertified) and are persisted on the order after a successful send (not inserted into email body).","operationId":"OrderController_sendOrderEmail","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOrderEmailDto"}}}},"responses":{"200":{"description":"Email sent successfully"},"400":{"description":"Payment not completed or other bad request"},"404":{"description":"Order or template not found"}},"security":[{"access-token":[]}],"summary":"Send order email with selected template","tags":["Order Controller"]}},"/orders/draft-attachments/{id}":{"post":{"description":"Uploads files to S3 and persists their metadata in the order so they survive page navigation. Returns the full current list of draft attachments for this order.","operationId":"OrderController_saveDraftAttachments","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"description":"One or more files to stage as draft attachments","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":"Draft attachments saved"}},"security":[{"access-token":[]}],"summary":"Upload draft attachments for an order email","tags":["Order Controller"]}},"/orders/draft-attachments/{id}/remove":{"patch":{"description":"Send JSON `{ \"url\": \"<full S3 URL>\" }` to remove that draft only. Omit `url` (or send an empty body) to remove all draft attachments for this order and delete their files from S3.","operationId":"OrderController_removeDraftAttachment","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Full HTTPS S3 URL of the draft file (same value as in `draftEmailAttachments[].url`). Omit to clear all."}}}}}},"responses":{"200":{"description":"Draft attachment(s) removed"}},"security":[{"access-token":[]}],"summary":"Remove a draft attachment (or all) for an order email","tags":["Order Controller"]}},"/orders/stop-abandonment/{id}":{"patch":{"description":"Toggle the stopAbandonmentEmails flag for a specific order.","operationId":"OrderController_toggleAbandonmentEmails","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleAbandonmentEmailsDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Stop or resume abandonment emails for an order","tags":["Order Controller"]}},"/orders/track/admin/{token}/document/{index}":{"get":{"operationId":"OrderTrackingController_downloadDocumentAdmin","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}},{"name":"index","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["OrderTracking"]}},"/orders/track/{token}":{"get":{"operationId":"OrderTrackingController_trackPage","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["OrderTracking"]}},"/orders/track/{token}/upsell":{"post":{"operationId":"OrderTrackingController_createUpsellFromTracking","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingPageUpsellDto"}}}},"responses":{"201":{"description":""}},"tags":["OrderTracking"]}},"/orders/track/{token}/ping":{"get":{"operationId":"OrderTrackingController_ping","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["OrderTracking"]}},"/orders/track/{token}/download-all":{"get":{"operationId":"OrderTrackingController_downloadAllFiles","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["OrderTracking"]}},"/orders/track/{token}/download/{index}":{"get":{"operationId":"OrderTrackingController_downloadFile","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}},{"name":"index","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["OrderTracking"]}},"/order-status":{"post":{"description":"Create a new order status with unique name validation.","operationId":"OrderStatusController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateOrderStatusDto"}}}},"responses":{"201":{"description":"Order status created successfully"},"400":{"description":"Order status with this name already exists"}},"security":[{"access-token":[]}],"summary":"Create order status","tags":["Order Status Controller"]},"get":{"description":"Retrieve order statuses with optional search by status name and pagination.","operationId":"OrderStatusController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by status name","schema":{"example":"Pending","type":"string"}},{"name":"isSystemDefined","required":false,"in":"query","description":"Filter by system defined status","schema":{"example":false,"type":"boolean"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string","enum":["status","createdAt","isSystemDefined"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Order statuses retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get order statuses with filters","tags":["Order Status Controller"]}},"/order-status/{id}":{"get":{"description":"Retrieve a single order status by its ID.","operationId":"OrderStatusController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Order status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusResponseDto"}}}},"404":{"description":"Order status not found"}},"security":[{"access-token":[]}],"summary":"Get order status by ID","tags":["Order Status Controller"]},"patch":{"description":"Update an existing order status. System-defined statuses cannot be updated.","operationId":"OrderStatusController_update","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateOrderStatusDto"}}}},"responses":{"200":{"description":"Order status updated successfully"},"400":{"description":"Order status with this name already exists"},"404":{"description":"Order status not found"}},"security":[{"access-token":[]}],"summary":"Update order status","tags":["Order Status Controller"]},"delete":{"description":"Soft delete an order status. System-defined statuses cannot be deleted.","operationId":"OrderStatusController_delete","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":"Order status deleted successfully"},"404":{"description":"Order status not found"}},"security":[{"access-token":[]}],"summary":"Delete order status","tags":["Order Status Controller"]}},"/order-status/transfer":{"post":{"description":"Transfer all orders from a source status to a target status. Both statuses must exist and be different.","operationId":"OrderStatusController_transferOrders","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrdersDto"}}}},"responses":{"200":{"description":"Orders transferred successfully"}},"security":[{"access-token":[]}],"summary":"Transfer orders from one status to another","tags":["Order Status Controller"]}},"/mail/send":{"post":{"description":"Send email and create log entry for tracking delivery and engagement. Supports attachment via multipart/form-data.","operationId":"MailController_sendEmail","parameters":[],"requestBody":{"required":true,"description":"Email data and optional files","content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SendEmailDto"}}}},"responses":{"200":{"description":"Email sent successfully"}},"summary":"Send email with metadata tracking (optional attachments)","tags":["Mail"]}},"/email-logs/statuses":{"get":{"operationId":"EmailLogController_getStatuses","parameters":[],"responses":{"200":{"description":"Email statuses retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"access-token":[]},{"access-token":[]}],"summary":"Get available email statuses","tags":["Email Logs"]}},"/email-logs":{"get":{"operationId":"EmailLogController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search text - works with searchBy to specify which field to search","schema":{"type":"string"}},{"name":"searchBy","required":false,"in":"query","description":"Search by email (recipient/sender), subject","schema":{"default":"byEmail","type":"string","enum":["byEmail","bySubject"]}},{"name":"fromDate","required":false,"in":"query","description":"Format: YYYY-MM-DD","schema":{"type":"string"}},{"name":"toDate","required":false,"in":"query","description":"Format: YYYY-MM-DD","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["Sent","Processed","Delivered","Opened","Clicked","Bounced","Deferred","Dropped","Spam Complaint","Spam Report","Unsubscribed","Group Unsubscribe","Group Resubscribe","Subscription Change","Failed"]}},{"name":"orderById","required":false,"in":"query","description":"Filter by order ID","schema":{"type":"number"}},{"name":"sortBy","required":false,"in":"query","schema":{"default":"createdAt","type":"string","enum":["createdAt","sentAt"]}},{"name":"sortType","required":false,"in":"query","schema":{"default":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"default":0,"type":"number"}},{"name":"size","required":false,"in":"query","description":"Items per page","schema":{"default":10,"type":"number"}}],"responses":{"200":{"description":"Email logs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailLogListResponseDto"}}}}},"security":[{"access-token":[]},{"access-token":[]}],"summary":"Get all email logs","tags":["Email Logs"]}},"/email-logs/attachments":{"delete":{"description":"Removes the file from S3 and strips it from this email log and any sibling rows with the same messageId. Identifies the row via body.emailLogId.","operationId":"EmailLogController_deleteAttachment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteEmailLogAttachmentDto"}}}},"responses":{"200":{"description":"Email attachment deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailLogDetailsResponseDto"}}}}},"security":[{"access-token":[]},{"access-token":[]}],"summary":"Delete an email attachment","tags":["Email Logs"]}},"/email-logs/{id}":{"get":{"operationId":"EmailLogController_getLog","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Email log retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailLogDetailsResponseDto"}}}}},"security":[{"access-token":[]},{"access-token":[]}],"summary":"Get email log by ID","tags":["Email Logs"]}},"/email-logs/history/{id}":{"get":{"operationId":"EmailLogController_getHistory","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Email history retrieved successfully"}},"security":[{"access-token":[]},{"access-token":[]}],"summary":"Get email history by log ID","tags":["Email Logs"]}},"/activity-logs":{"get":{"description":"Retrieve activity logs with optional filters by module, action, status, user, date range, etc.","operationId":"ActivityLogController_findAll","parameters":[{"name":"toDate","required":false,"in":"query","schema":{"example":"2024-12-31","type":"string"}},{"name":"fromDate","required":false,"in":"query","schema":{"example":"2024-01-01","type":"string"}},{"name":"userEmail","required":false,"in":"query","schema":{"example":"john@example.com","type":"string"}},{"name":"userId","required":false,"in":"query","schema":{"example":"1","type":"string"}},{"name":"action","required":false,"in":"query","schema":{"enum":["CREATE","UPDATE","DELETE","LOGIN","LOGOUT","VIEW","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELED","PAYMENT_PROCESSING","EMAIL_SENT","DOCUMENT_VIEW","DOCUMENT_DOWNLOAD","OTHER"],"type":"string"}},{"name":"module","required":false,"in":"query","schema":{"example":"orders","type":"string"}},{"name":"search","required":false,"in":"query","schema":{"example":"order created","type":"string"}},{"name":"size","required":true,"in":"query","schema":{"example":10,"type":"number"}},{"name":"page","required":true,"in":"query","schema":{"example":0,"type":"number"}}],"responses":{"200":{"description":"Activity logs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllActivityLogsResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get activity logs with filters","tags":["Activity Log Controller"]}},"/activity-logs/{id}":{"get":{"description":"Get complete activity log details by ID","operationId":"ActivityLogController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityLogDetailResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get activity log by ID","tags":["Activity Log Controller"]}},"/notifications/fcm-token":{"post":{"description":"Call this after getting the FCM token from Firebase in your frontend. Each browser/device registers its own token.","operationId":"NotificationsController_registerToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterFcmTokenDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Register FCM token for push notifications","tags":["Notifications"]},"delete":{"description":"Call this when user logs out from a specific browser/device. Only that device will stop receiving notifications.","operationId":"NotificationsController_removeToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveFcmTokenDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Remove FCM token on logout","tags":["Notifications"]}},"/notifications/fcm-token/all":{"delete":{"description":"Use this for \"logout from all devices\" functionality.","operationId":"NotificationsController_removeAllTokens","parameters":[],"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Remove all FCM tokens for current user (all devices)","tags":["Notifications"]}},"/notifications/push-preference":{"patch":{"operationId":"NotificationsController_updateMyPushPreference","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePushPreferenceDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Enable/disable push notifications for current user","tags":["Notifications"]}},"/task-status":{"post":{"operationId":"TaskStatusController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateTaskStatusDto"}}}},"responses":{"201":{"description":"Task status created successfully"}},"security":[{"access-token":[]}],"summary":"Create task status","tags":["Task Status Controller"]},"get":{"operationId":"TaskStatusController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by status name","schema":{"example":"To Do","type":"string"}},{"name":"isSystemDefined","required":false,"in":"query","description":"Filter by system defined status","schema":{"example":true,"type":"boolean"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string","enum":["status","createdAt","isSystemDefined"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Task statuses retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskStatusListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get task statuses with filters","tags":["Task Status Controller"]}},"/task-status/{id}":{"get":{"operationId":"TaskStatusController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Task status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskStatusResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get task status by ID","tags":["Task Status Controller"]},"patch":{"operationId":"TaskStatusController_update","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateTaskStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Update task status","tags":["Task Status Controller"]},"delete":{"operationId":"TaskStatusController_delete","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Delete task status","tags":["Task Status Controller"]}},"/task-status/transfer":{"post":{"operationId":"TaskStatusController_transferTasks","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferTasksDto"}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Transfer tasks from one status to another","tags":["Task Status Controller"]}},"/orders/{orderId}/tasks":{"get":{"operationId":"OrderTaskController_findByOrder","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"assignedTo","required":false,"in":"query","description":"Filter by assigned user ID","schema":{"example":5,"type":"number"}},{"name":"taskStatusId","required":false,"in":"query","description":"Filter by task status ID","schema":{"example":1,"type":"number"}},{"name":"isOverdue","required":false,"in":"query","description":"Filter overdue tasks only","schema":{"example":true,"type":"boolean"}},{"name":"isCompleted","required":false,"in":"query","description":"Filter completed tasks when true, non-completed when false. Defaults to false when taskStatusId is not provided.","schema":{"default":false,"example":false,"type":"boolean"}},{"name":"priority","required":false,"in":"query","description":"Filter by priority","schema":{"type":"string","enum":["low","medium","high"]}},{"name":"search","required":false,"in":"query","description":"Search in title and description","schema":{"example":"follow up","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string","enum":["title","createdAt","dueDate","priority","updatedAt"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Page size","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Tasks retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"List tasks for an order","tags":["Order Tasks Controller"]},"post":{"operationId":"OrderTaskController_create","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Send as multipart/form-data when attaching files, or application/json without files.","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Follow up with customer"},"description":{"type":"string"},"taskStatusId":{"type":"number"},"priority":{"type":"string","enum":["low","medium","high"]},"dueDate":{"type":"string","format":"date-time"},"assignedTo":{"type":"number","nullable":true},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"Up to 10 files"}},"required":["title"]}},"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Follow up with customer"},"description":{"type":"string"},"taskStatusId":{"type":"number"},"priority":{"type":"string","enum":["low","medium","high"]},"dueDate":{"type":"string","format":"date-time"},"assignedTo":{"type":"number","nullable":true},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"Up to 10 files"}},"required":["title"]}}}},"responses":{"201":{"description":"Task created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Create task for an order (optional media files, max 10)","tags":["Order Tasks Controller"]}},"/orders/{orderId}/tasks/{taskId}":{"get":{"operationId":"OrderTaskController_findOne","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"taskId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Task retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get task by ID for an order","tags":["Order Tasks Controller"]},"patch":{"operationId":"OrderTaskController_update","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"taskId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Multipart when uploading files; include removeMediaIds as JSON array string e.g. \"[1,2]\"","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"taskStatusId":{"type":"number"},"priority":{"type":"string","enum":["low","medium","high"]},"dueDate":{"type":"string","format":"date-time","nullable":true},"assignedTo":{"type":"number","nullable":true},"removeMediaIds":{"type":"string","example":"1","description":"Media IDs to delete — single id (1), JSON array ([1,2]), or comma-separated (1,2)"},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"New files to append (max 10 total per task)"}}}},"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"taskStatusId":{"type":"number"},"priority":{"type":"string","enum":["low","medium","high"]},"dueDate":{"type":"string","format":"date-time","nullable":true},"assignedTo":{"type":"number","nullable":true},"removeMediaIds":{"type":"string","example":"1","description":"Media IDs to delete — single id (1), JSON array ([1,2]), or comma-separated (1,2)"},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"New files to append (max 10 total per task)"}}}}}},"responses":{"200":{"description":"Task updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Update task — optional new files (append), removeMediaIds, max 10 total media","tags":["Order Tasks Controller"]},"delete":{"operationId":"OrderTaskController_delete","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"taskId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Task deleted successfully"}},"security":[{"access-token":[]}],"summary":"Delete task for an order (soft delete)","tags":["Order Tasks Controller"]}},"/orders/{orderId}/tasks/{taskId}/media":{"post":{"operationId":"OrderTaskController_uploadMedia","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"taskId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Append media files to a task (max 10 total per task)","tags":["Order Tasks Controller"]}},"/orders/{orderId}/tasks/{taskId}/media/{mediaId}":{"delete":{"operationId":"OrderTaskController_deleteMedia","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"taskId","required":true,"in":"path","schema":{"type":"number"}},{"name":"mediaId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"access-token":[]}],"summary":"Delete task media file","tags":["Order Tasks Controller"]}},"/tasks/assignees":{"get":{"operationId":"TaskController_findAssignableUsers","parameters":[],"responses":{"200":{"description":"Assignable users retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskAssigneeOptionDto"}}}}}},"security":[{"access-token":[]}],"summary":"List users available for task assignment","tags":["Tasks Controller"]}},"/tasks":{"get":{"description":"Returns paginated tasks with filters. By default excludes Completed tasks (same as order task list). Pass isCompleted=true to see only completed tasks, or taskStatusId to filter by a specific status.","operationId":"TaskController_findAll","parameters":[{"name":"assignedTo","required":false,"in":"query","description":"Filter by assigned user ID","schema":{"example":5,"type":"number"}},{"name":"taskStatusId","required":false,"in":"query","description":"Filter by task status ID","schema":{"example":1,"type":"number"}},{"name":"isOverdue","required":false,"in":"query","description":"Filter overdue tasks only","schema":{"example":true,"type":"boolean"}},{"name":"isCompleted","required":false,"in":"query","description":"Filter completed tasks when true, non-completed when false. Defaults to false when taskStatusId is not provided.","schema":{"default":false,"example":false,"type":"boolean"}},{"name":"priority","required":false,"in":"query","description":"Filter by priority","schema":{"type":"string","enum":["low","medium","high"]}},{"name":"search","required":false,"in":"query","description":"Search in title and description","schema":{"example":"follow up","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string","enum":["title","createdAt","dueDate","priority","updatedAt"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Page size","schema":{"example":10,"type":"number"}},{"name":"orderId","required":false,"in":"query","description":"Filter by order ID","schema":{"example":1001,"type":"number"}}],"responses":{"200":{"description":"Tasks retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"List tasks across all orders","tags":["Tasks Controller"]}},"/customers/check-email":{"post":{"description":"Check if a customer with the given email address exists","operationId":"CustomersController_checkEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckEmailDto"}}}},"responses":{"200":{"description":"Email check completed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckEmailResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Check if customer exists with email","tags":["Customers Controller"]}},"/customers":{"post":{"description":"Create a new customer","operationId":"CustomersController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerDto"}}}},"responses":{"201":{"description":"Customer created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Create customer","tags":["Customers Controller"]},"patch":{"description":"Update customer","operationId":"CustomersController_update","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerDto"}}}},"responses":{"200":{"description":"Customer updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}}},"summary":"Update customer","tags":["Customers Controller"]}},"/customers/{id}":{"get":{"description":"Get customer by ID","operationId":"CustomersController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Customer retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get customer by ID","tags":["Customers Controller"]}},"/customers/verify-email":{"post":{"description":"Verifies an email using 3rd party API and updates customer status","operationId":"CustomersController_verifyEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailDto"}}}},"responses":{"200":{"description":"Email verification completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Verify email address","tags":["Customers Controller"]}},"/cart-abandonment/process":{"post":{"operationId":"CartAbandonmentController_processCartAbandonment","parameters":[],"responses":{"200":{"description":"Cart abandonment emails processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessingSummaryResponseDto"}}}}},"summary":"Manually trigger cart abandonment email processing","tags":["Cart Abandonment"]}},"/cart-abandonment/process/{orderId}":{"post":{"operationId":"CartAbandonmentController_processOrder","parameters":[{"name":"orderId","required":true,"in":"path","description":"Order ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Order processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualProcessingResponseDto"}}}}},"summary":"Manually process specific order","tags":["Cart Abandonment"]}},"/cart-abandonment/config":{"get":{"operationId":"CartAbandonmentController_getStageConfigs","parameters":[],"responses":{"200":{"description":"Stage configurations retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StageConfigResponseDto"}}}}}},"summary":"Get stage configurations","tags":["Cart Abandonment"]}},"/email-templates":{"post":{"description":"Create a new email template with optional upsell products","operationId":"EmailTemplateController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailTemplateDto"}}}},"responses":{"201":{"description":"Email template created successfully"}},"security":[{"access-token":[]}],"summary":"Create a new email template","tags":["Email Templates"]},"get":{"description":"Retrieve all active email templates","operationId":"EmailTemplateController_findAll","parameters":[],"responses":{"200":{"description":"Email templates retrieved successfully"}},"security":[{"access-token":[]}],"summary":"Get all email templates","tags":["Email Templates"]}},"/email-templates/{id}":{"get":{"description":"Retrieve a specific email template by its ID","operationId":"EmailTemplateController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Email template retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTemplateResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get email template by ID","tags":["Email Templates"]},"put":{"description":"Update an existing email template","operationId":"EmailTemplateController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailTemplateDto"}}}},"responses":{"200":{"description":"Email template updated successfully"}},"security":[{"access-token":[]}],"summary":"Update email template","tags":["Email Templates"]},"delete":{"description":"Soft delete an email template","operationId":"EmailTemplateController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Email template deleted successfully"}},"security":[{"access-token":[]}],"summary":"Delete email template","tags":["Email Templates"]}},"/employees":{"post":{"operationId":"EmployeeController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmployeeDto"}}}},"responses":{"201":{"description":"Employee created successfully."}},"security":[{"access-token":[]}],"summary":"Create a new employee","tags":["Employee Management"]},"get":{"operationId":"EmployeeController_findAll","parameters":[{"name":"search","required":false,"in":"query","description":"Search by first name, last name, or email","schema":{"example":"John","type":"string"}},{"name":"byRole","required":false,"in":"query","description":"Filter by role","schema":{"example":"employee","type":"string","enum":["admin","employee"]}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":false,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by (e.g., id, firstName, lastName, email, createdAt)","schema":{"example":"createdAt","type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order (ASC or DESC)","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}}],"responses":{"200":{"description":"Return all employees."}},"security":[{"access-token":[]}],"summary":"Get all employees","tags":["Employee Management"]}},"/employees/change-status/{id}":{"patch":{"operationId":"EmployeeController_toggleStatus","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleStatusEmployeeDto"}}}},"responses":{"200":{"description":"Employee status updated successfully."}},"security":[{"access-token":[]}],"summary":"Toggle employee active/inactive status","tags":["Employee Management"]}},"/employees/{id}":{"get":{"operationId":"EmployeeController_findOne","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":"Return the employee."}},"security":[{"access-token":[]}],"summary":"Get employee by id","tags":["Employee Management"]},"patch":{"operationId":"EmployeeController_update","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmployeeDto"}}}},"responses":{"200":{"description":"Employee updated successfully."}},"security":[{"access-token":[]}],"summary":"Update an employee","tags":["Employee Management"]},"delete":{"operationId":"EmployeeController_remove","parameters":[{"name":"id","required":true,"in":"path","description":"The ID of the entity","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":"Employee deleted successfully."}},"security":[{"access-token":[]}],"summary":"Delete (soft delete) an employee","tags":["Employee Management"]}},"/dashboard/orders-by-country":{"get":{"description":"Per-country order counts, upsell counts by source (order page, email, admin, document link), GBP totals (`totalAmount`, `refundAmount`, `netSalesAmount`), and checkout-currency totals (`totalAmountLocal`, `refundAmountLocal`, `netSalesAmountLocal`, `currency`, `currencySymbol`). Includes `upsellReport` (`{ source, count, percentage }`), `upsellEntryChannelReport` (Document Link entry channels with % of Document Link and of all upsells), and `documentLinkReminderReport` (reminder day/time/stage + GBP). Attribution reports are stored in daily `orders_by_country` cache and served via the same hybrid cache path as country stats (legacy cache days fall back to live calc).","operationId":"DashboardController_getStatistics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Dashboard statistics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardStatsResponseDto"}}}}},"summary":"Get country-wise dashboard statistics","tags":["Dashboard"]}},"/dashboard/order-statistics":{"get":{"description":"Returns Total Orders, Revenue, Avg Order Value, and Pending count with percentage changes. Default range: yesterday to today.","operationId":"DashboardController_getOrderStatistics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Order statistics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatisticsResponseDto"}}}}},"summary":"Get order statistics with date range","tags":["Dashboard"]}},"/dashboard/fast-track-by-country":{"get":{"description":"Returns count of orders with isExpressDelivery=true grouped by country. Supports date range filtering. Default range: yesterday to today. Countries with 0 express orders are included.","operationId":"DashboardController_getFastTrackByCountry","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Fast track statistics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastTrackResponseDto"}}}}},"summary":"Get express delivery orders count by country","tags":["Dashboard"]}},"/dashboard/fast-track-ratio-hourly":{"get":{"description":"Get hourly cumulative fast track ratio in 7-hour time slots. Shows percentage of express delivery orders for each slot. Supports optional date range filtering. Defaults to last 7 days.","operationId":"DashboardController_getFastTrackRatioHourly","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Fast track ratio hourly data retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastTrackRatioHourlyResponseDto"}}}}},"summary":"Get fast track ratio hourly cumulative","tags":["Dashboard"]}},"/dashboard/fast-track-ratio-cumulative":{"get":{"description":"Get CUMULATIVE fast track ratio in 7-hour time slots. Shows running total percentage from start to each slot. Supports optional date range filtering. Defaults to last 7 days.","operationId":"DashboardController_getFastTrackRatioCumulative","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Fast track ratio cumulative data retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastTrackRatioHourlyResponseDto"}}}}},"summary":"Get fast track ratio cumulative","tags":["Dashboard"]}},"/dashboard/keyword-report":{"get":{"description":"Get aggregated keyword report including sales count, revenue, avg order value, and products sold. Groups by utmTerm or utmSource.","operationId":"DashboardController_getKeywordReport","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Keyword report retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeywordReportResponseDto"}}}}},"summary":"Get keyword report","tags":["Dashboard"]}},"/dashboard/utm-source-statistics":{"get":{"description":"Returns `utmSourceByCountry` (orders per country × normalized utmSource), `utmSourceRatio` (share of orders per source — all sources, sorted by count), and `utmSourceBySource` (sales count, net revenue GBP, AOV, multi-document metrics per source). Respects the same date range and excluded order statuses as other dashboard order reports.","operationId":"DashboardController_getUtmSourceStatistics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"UTM source statistics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UtmSourceStatisticsResponseDto"}}}}},"summary":"Get UTM source statistics","tags":["Dashboard"]}},"/dashboard/abandonment-recovery-statistics":{"get":{"description":"Returns summary, recovered/not recovered ratio, and country-wise breakdown for orders successfully paid after an abandonment email was sent. Respects the same date range, UTM source filter, and excluded order statuses as other dashboard order reports.","operationId":"DashboardController_getAbandonmentRecoveryStatistics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Abandonment recovery statistics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbandonmentRecoveryStatisticsResponseDto"}}}}},"summary":"Get abandonment recovery statistics","tags":["Dashboard"]}},"/dashboard/order-metrics":{"get":{"description":"Get all key order metrics: Average Order Value, Multiple Document Ratio, Fast Track Ratio, and Paper Copy Ratio","operationId":"DashboardController_getOrderMetrics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Order metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderMetricsResponseDto"}}}}},"summary":"Get comprehensive order metrics","tags":["Dashboard"]}},"/dashboard/purchase-analytics":{"get":{"description":"Get all purchase analytics: Purchase Value by Currency, Purchase Value by Payment Method, and Purchase Count by OS.","operationId":"DashboardController_getPurchaseAnalytics","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Purchase analytics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseAnalyticsResponseDto"}}}}},"summary":"Get comprehensive purchase analytics","tags":["Dashboard"]}},"/dashboard/fast-track-count-by-os":{"get":{"description":"Returns count of express delivery orders grouped by OS. Excludes System Generated orders.","operationId":"DashboardController_getFastTrackCountByOS","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Fast track counts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastTrackCountByOSResponseDto"}}}}},"summary":"Get fast track count grouped by Operating System","tags":["Dashboard"]}},"/dashboard/paper-copy-count-by-os":{"get":{"description":"Returns count of orders with isRequestedPaperCopy=true grouped by OS. Excludes System Generated orders.","operationId":"DashboardController_getPaperCopyCountByOS","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Paper copy counts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaperCopyCountByOSResponseDto"}}}}},"summary":"Get paper copy count grouped by Operating System","tags":["Dashboard"]}},"/dashboard/employee-completed-orders":{"get":{"description":"Returns count of orders completed (status Completed only) by each user for pie chart display.","operationId":"DashboardController_getEmployeeCompletedOrders","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Employee completed orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeCompletedOrdersResponseDto"}}}}},"summary":"Get completed orders grouped by employee","tags":["Dashboard"]}},"/dashboard/employee-printed-orders":{"get":{"description":"Returns count of orders marked Printed by each user for pie chart display.","operationId":"DashboardController_getEmployeePrintedOrders","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Employee printed orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeePrintedOrdersResponseDto"}}}}},"summary":"Get Printed orders grouped by employee","tags":["Dashboard"]}},"/dashboard/hourly-trends":{"get":{"description":"Returns hourly \"Average order value\" and \"Fast track counts\".","operationId":"DashboardController_getHourlyTrends","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Hourly trends retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HourlyTrendsResponseDto"}}}}},"summary":"Get hourly trend analytics","tags":["Dashboard"]}},"/dashboard/product-wise-sales":{"get":{"description":"Get sales count grouped by product. Analyzes products JSONB array from orders and returns count per product. Excludes System Generated orders. Supports optional date range filtering.","operationId":"DashboardController_getProductWiseSales","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Product wise sales retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductWiseSalesResponseDto"}}}}},"summary":"Get product wise sales","tags":["Dashboard"]}},"/dashboard/revenue-by-currency":{"get":{"description":"Returns gross revenue, refunded amount and net revenue grouped by currency for all currencies present in DB.","operationId":"DashboardController_getRevenueByCurrency","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date for filtering (ISO 8601 format)","schema":{"example":"2026-01-01","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date for filtering (ISO 8601 format)","schema":{"example":"2026-01-13","type":"string"}},{"name":"utmSource","required":false,"in":"query","description":"Optional UTM source filter (exact match after TRIM). Use \"notSet\" for orders with no UTM source (NULL, empty, or whitespace).","schema":{"example":"google","type":"string"}}],"responses":{"200":{"description":"Revenue by currency retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueByCurrencyResponseDto"}}}}},"summary":"Get revenue breakdown by currency","tags":["Dashboard"]}},"/dashboard/keyword-ratio":{"get":{"description":"Open endpoint — no authentication required. Accepts a keyword matched against utmTerm. Returns ratio = (express delivery orders for keyword / total orders for keyword) * 100 over the rolling window defined by FAST_TRACK_RATIO_WINDOW env var (e.g. \"1d\", \"30d\"). eligibleForFastTrack = true when ratio is within [FAST_TRACK_MIN_RATIO, FAST_TRACK_MAX_RATIO] (both inclusive).","operationId":"DashboardController_getKeywordRatio","parameters":[{"name":"keyword","required":true,"in":"query","description":"Keyword to look up — matched against utmTerm field.","schema":{"example":"land registry search","type":"string"}}],"responses":{"200":{"description":"Keyword ratio and fast-track eligibility returned successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeywordRatioResponseDto"}}}}},"summary":"Get fast-track eligibility ratio for a keyword (open API)","tags":["Dashboard"]}},"/api/analytics/orders":{"get":{"operationId":"AnalyticsController_getOrders","parameters":[],"responses":{"200":{"description":""}},"tags":["Analytics"]}},"/api/analytics/dashboard":{"get":{"operationId":"AnalyticsController_getDashboard","parameters":[],"responses":{"200":{"description":""}},"tags":["Analytics"]}},"/upsell-rules/recommend":{"get":{"description":"Internal/Admin only API to get upsell product recommendations based on ordered product IDs and country.","operationId":"UpsellRuleController_getRecommendation","parameters":[{"name":"productIds","required":true,"in":"query","description":"Comma-separated product IDs","schema":{"example":"2,3","type":"string"}},{"name":"countryId","required":true,"in":"query","description":"Country ID","schema":{"example":5,"type":"number"}}],"responses":{"200":{"description":"Upsell recommendation retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsellRecommendationResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get upsell recommendation","tags":["Upsell Rule Controller"]}},"/upsell-rules":{"post":{"description":"Create a new upsell rule mapping source products to upsell products.","operationId":"UpsellRuleController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpsellRuleDto"}}}},"responses":{"201":{"description":"Upsell rule created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsellRuleResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Create upsell rule","tags":["Upsell Rule Controller"]},"get":{"description":"Retrieve upsell rules with optional filters by country and active status.","operationId":"UpsellRuleController_findAll","parameters":[{"name":"page","required":true,"in":"query","description":"Page number for pagination","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Number of items per page","schema":{"example":10,"type":"number"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country","schema":{"example":5,"type":"number"}},{"name":"isActive","required":false,"in":"query","description":"Filter by active status","schema":{"example":true,"type":"boolean"}}],"responses":{"200":{"description":"Upsell rules retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsellRuleListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get all upsell rules","tags":["Upsell Rule Controller"]}},"/upsell-rules/{id}":{"get":{"description":"Get a specific upsell rule by its ID.","operationId":"UpsellRuleController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Upsell rule retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsellRuleResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Get upsell rule by ID","tags":["Upsell Rule Controller"]},"patch":{"description":"Update an existing upsell rule.","operationId":"UpsellRuleController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUpsellRuleDto"}}}},"responses":{"200":{"description":"Upsell rule updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsellRuleResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"Update upsell rule","tags":["Upsell Rule Controller"]},"delete":{"description":"Delete an upsell rule (admin only).","operationId":"UpsellRuleController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Upsell rule deleted successfully"}},"security":[{"access-token":[]}],"summary":"Delete upsell rule","tags":["Upsell Rule Controller"]}},"/zendesk/tickets":{"post":{"description":"Creates a ticket: requester = order customerEmail; notification From = countries.supportMail for order country. If that address is not yet in Zendesk, it is created as a support address (requires API permissions), then the ticket is opened. Assignee (and submitter / first comment author) is resolved from the user zendeskAgentEmail or the default agent. Optional customStatusId sets the initial custom ticket status (from GET /zendesk/tickets/statuses).","operationId":"ZendeskController_createTicket","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicketDto"}}}},"responses":{"201":{"description":"Ticket created successfully"}},"security":[{"access-token":[]}],"summary":"Create a Zendesk ticket","tags":["Zendesk Controller"]}},"/zendesk/tickets/find":{"get":{"description":"Searches for tickets in Zendesk using the customer email address","operationId":"ZendeskController_findTickets","parameters":[{"name":"email","required":true,"in":"query","description":"The customer email to find tickets for","schema":{"example":"customer@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"The page number","schema":{"default":1,"example":1,"type":"number"}},{"name":"per_page","required":false,"in":"query","description":"The number of tickets per page","schema":{"default":20,"example":20,"type":"number"}}],"responses":{"200":{"description":"Tickets found successfully"}},"security":[{"access-token":[]}],"summary":"Find tickets by customer email","tags":["Zendesk Controller"]}},"/zendesk/tickets/statuses":{"get":{"description":"Fetches the list of custom ticket statuses from Zendesk","operationId":"ZendeskController_getStatuses","parameters":[],"responses":{"200":{"description":"Statuses fetched successfully"}},"security":[{"access-token":[]}],"summary":"Get available ticket statuses","tags":["Zendesk Controller"]}},"/zendesk/agents":{"get":{"description":"Fetches the list of all agents and admins from Zendesk","operationId":"ZendeskController_getAgents","parameters":[],"responses":{"200":{"description":"Agents fetched successfully"}},"security":[{"access-token":[]}],"summary":"Get list of Zendesk agents","tags":["Zendesk Controller"]}},"/zendesk/tickets/{ticketId}/comments":{"get":{"description":"Fetches comments and associated user details for a ticket","operationId":"ZendeskController_getComments","parameters":[{"name":"ticketId","required":true,"in":"path","description":"The Zendesk ticket ID","schema":{"example":1,"type":"number"}}],"responses":{"200":{"description":"Comments fetched successfully"}},"security":[{"access-token":[]}],"summary":"Get comments for a ticket","tags":["Zendesk Controller"]}},"/zendesk/tickets/{ticketId}/reply":{"put":{"description":"Adds a public or private comment. Comment author is the logged-in user's zendeskAgentEmail when that agent exists in Zendesk; otherwise the default agent.","operationId":"ZendeskController_reply","parameters":[{"name":"ticketId","required":true,"in":"path","description":"The Zendesk ticket ID","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyToTicketDto"}}}},"responses":{"200":{"description":"Reply added successfully"}},"security":[{"access-token":[]}],"summary":"Reply to a ticket","tags":["Zendesk Controller"]}},"/zendesk/tickets/{ticketId}/status":{"put":{"description":"Updates the custom status of a Zendesk ticket","operationId":"ZendeskController_updateStatus","parameters":[{"name":"ticketId","required":true,"in":"path","description":"The Zendesk ticket ID","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTicketStatusDto"}}}},"responses":{"200":{"description":"Status updated successfully"}},"security":[{"access-token":[]}],"summary":"Update ticket status","tags":["Zendesk Controller"]}},"/zendesk/tickets/{ticketId}/assign":{"put":{"description":"Updates the assignee of a Zendesk ticket","operationId":"ZendeskController_assignAgent","parameters":[{"name":"ticketId","required":true,"in":"path","description":"The Zendesk ticket ID","schema":{"example":1,"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignAgentDto"}}}},"responses":{"200":{"description":"Agent assigned successfully"}},"security":[{"access-token":[]}],"summary":"Assign a ticket to an agent","tags":["Zendesk Controller"]}},"/orders/{orderId}/internal-documents":{"post":{"operationId":"OrderInternalDocumentController_upload","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Use multipart/form-data with \"files\". Optional title/notes are applied to uploaded files.","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"title":{"type":"string"},"notes":{"type":"string"},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"Up to 10 files"}},"required":["files"]}},"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"notes":{"type":"string"},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"Up to 10 files"}},"required":["files"]}}}},"responses":{"201":{"description":"Internal document(s) uploaded successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrderInternalDocumentDto"}}}}}},"security":[{"access-token":[]}],"summary":"Upload one or more internal documents for an order","tags":["Order Internal Documents"]},"get":{"operationId":"OrderInternalDocumentController_list","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"uploadedBy","required":false,"in":"query","description":"Filter by uploader user ID","schema":{"example":8,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search in title, original file name, and notes","schema":{"example":"registry","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"id","type":"string","enum":["id","createdAt","updatedAt","title","originalFileName","orderId"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Page size","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Internal documents retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderInternalDocumentListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"List internal documents for an order","tags":["Order Internal Documents"]}},"/orders/{orderId}/internal-documents/{documentId}":{"patch":{"description":"Update title and/or notes. Optionally send a single \"file\" to replace the stored document. Omit title/notes to leave them unchanged; empty string clears to null.","operationId":"OrderInternalDocumentController_update","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"documentId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Multipart when replacing the file; JSON is fine for metadata-only updates.","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"file":{"type":"string","format":"binary","description":"Optional replacement file"}}}},"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"file":{"type":"string","format":"binary","description":"Optional replacement file"}}}}}},"responses":{"200":{"description":"Internal document updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderInternalDocumentDto"}}}}},"security":[{"access-token":[]}],"summary":"Update internal document metadata and/or replace the file","tags":["Order Internal Documents"]},"delete":{"operationId":"OrderInternalDocumentController_delete","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"number"}},{"name":"documentId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Internal document deleted successfully"}},"security":[{"access-token":[]}],"summary":"Delete internal document","tags":["Order Internal Documents"]}},"/internal-documents":{"get":{"description":"Paginated global list of active internal documents. Filter by orderId, uploadedBy, or search title/file name/notes.","operationId":"InternalDocumentController_findAll","parameters":[{"name":"orderId","required":false,"in":"query","description":"Filter by order ID","schema":{"example":1302,"type":"number"}},{"name":"uploadedBy","required":false,"in":"query","description":"Filter by uploader user ID","schema":{"example":8,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search in title, original file name, and notes","schema":{"example":"registry","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"example":"createdAt","type":"string","enum":["id","createdAt","updatedAt","title","originalFileName","orderId"]}},{"name":"sortType","required":false,"in":"query","description":"Sort direction","schema":{"example":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":true,"in":"query","description":"Page number","schema":{"example":0,"type":"number"}},{"name":"size","required":true,"in":"query","description":"Page size","schema":{"example":10,"type":"number"}}],"responses":{"200":{"description":"Internal documents retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderInternalDocumentListResponseDto"}}}}},"security":[{"access-token":[]}],"summary":"List internal documents across all orders","tags":["Internal Documents"]}}},"info":{"title":"Land Registry API","description":"Land Registry Management System API\n \n<a href=\"https://api.findmydocument.net/swagger/download\" target=\"_blank\" style=\"background-color: #4CAF50; color: white; padding: 8px 16px; text-decoration: none; border-radius: 4px; font-weight: bold;\">Download Swagger JSON</a>","version":"1.0","contact":{}},"tags":[],"servers":[{"url":"https://api.findmydocument.net/"}],"components":{"securitySchemes":{"access-token":{"scheme":"Bearer","bearerFormat":"Bearer","description":"Please enter token in following format: Bearer <JWT>","name":"Authorization","type":"http","in":"Header"}},"schemas":{"LoginDto":{"type":"object","properties":{"email":{"type":"string","description":"User email address","example":"admin@landregistry.com"},"password":{"type":"string","description":"User password","example":"admin@123","minLength":6}},"required":["email","password"]},"UserResponse":{"type":"object","properties":{"id":{"type":"number","description":"User ID"},"email":{"type":"string","description":"User email"},"firstName":{"type":"string","description":"User first name"},"lastName":{"type":"string","description":"User last name"},"role":{"type":"string","description":"User role"}},"required":["id","email","firstName","lastName","role"]},"LoginResponseDto":{"type":"object","properties":{"access_token":{"type":"string","description":"JWT access token"},"refresh_token":{"type":"string","description":"JWT refresh token"},"userDetails":{"description":"User information","allOf":[{"$ref":"#/components/schemas/UserResponse"}]}},"required":["access_token","refresh_token","userDetails"]},"RefreshTokenDto":{"type":"object","properties":{"refresh_token":{"type":"string","description":"JWT refresh token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["refresh_token"]},"CreateCountryDto":{"type":"object","properties":{"countryName":{"type":"string","description":"Country name","example":"United States","maxLength":100,"minLength":2},"domain":{"type":"string","description":"Country domain","example":"example.com","maxLength":255},"currencyCode":{"type":"string","description":"ISO 4217 currency code (3 uppercase letters)","example":"USD","maxLength":3,"minLength":3},"currencySymbol":{"type":"string","description":"Currency symbol","example":"$","maxLength":10,"minLength":1},"mailFrom":{"type":"string","description":"Email address to use as sender for emails related to this country","example":"noreply@uklandregistryonline.org.uk","maxLength":255},"supportMail":{"type":"string","description":"Support email address for customer inquiries related to this country","example":"support@uklandregistryonline.org.uk","maxLength":255},"emailSignature":{"type":"string","description":"Email signature for this country","example":"Best regards, UK Land Registry Team"},"displayName":{"type":"string","description":"Display name for this country (used in UI/emails)","example":"UK Land Registry","maxLength":255}},"required":["countryName","domain","currencyCode","currencySymbol","mailFrom","supportMail"]},"CountryResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Country ID","example":1},"countryName":{"type":"string","description":"Country name","example":"United States"},"currencyCode":{"type":"string","description":"ISO 4217 currency code","example":"USD"},"currencySymbol":{"type":"string","description":"Currency symbol","example":"$"},"mailFrom":{"type":"string","description":"Email address used as sender for emails","example":"noreply@uklandregistryonline.org.uk"},"supportMail":{"type":"string","description":"Support email address for customer inquiries","example":"support@uklandregistryonline.org.uk"},"isActive":{"type":"boolean","description":"Active status of the country","example":true},"isDeleted":{"type":"boolean","description":"Deleted status of the country","example":false},"emailSignature":{"type":"string","description":"Email signature for the country","example":"Best regards, Team","nullable":true},"displayName":{"type":"string","description":"Display name for the country","example":"UK Land Registry","nullable":true}},"required":["id","countryName","currencyCode","currencySymbol","mailFrom","supportMail","isActive","isDeleted","emailSignature","displayName"]},"UpdateCountryDto":{"type":"object","properties":{"countryName":{"type":"string","description":"Country name","example":"United States","maxLength":100,"minLength":2},"domain":{"type":"string","description":"Country domain","example":"example.com","maxLength":255},"currencyCode":{"type":"string","description":"ISO 4217 currency code (3 uppercase letters)","example":"USD","maxLength":3,"minLength":3},"currencySymbol":{"type":"string","description":"Currency symbol","example":"$","maxLength":10,"minLength":1},"mailFrom":{"type":"string","description":"Email address to use as sender for emails related to this country","example":"noreply@uklandregistryonline.org.uk","maxLength":255},"supportMail":{"type":"string","description":"Support email address for customer inquiries related to this country","example":"support@uklandregistryonline.org.uk","maxLength":255},"emailSignature":{"type":"string","description":"Email signature for this country","example":"Best regards, UK Land Registry Team"},"displayName":{"type":"string","description":"Display name for this country (used in UI/emails)","example":"UK Land Registry","maxLength":255}}},"CreateStateDto":{"type":"object","properties":{"countryId":{"type":"number","description":"ID of the country this state belongs to","example":1},"stateName":{"type":"string","description":"State name","example":"California","maxLength":100,"minLength":2},"externalLink":{"type":"string","description":"External domain URL for this state","example":"example.com","maxLength":255,"nullable":true},"isActive":{"type":"boolean","description":"Whether the state is active","example":true,"default":true}},"required":["countryId","stateName"]},"StateResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"State ID","example":1},"countryId":{"type":"number","description":"ID of the country this state belongs to","example":1},"stateName":{"type":"string","description":"State name","example":"California"},"externalLink":{"type":"string","description":"External domain URL for this state","example":"example.com","nullable":true},"isActive":{"type":"boolean","description":"Active status of the state","example":true},"isDeleted":{"type":"boolean","description":"Deleted status of the state","example":false},"country":{"description":"Related country information","allOf":[{"$ref":"#/components/schemas/CountryResponseDto"}]}},"required":["id","countryId","stateName","externalLink","isActive","isDeleted","country"]},"UpdateStateDto":{"type":"object","properties":{"countryId":{"type":"number","description":"ID of the country this state belongs to","example":1},"stateName":{"type":"string","description":"State name","example":"California","maxLength":100,"minLength":2},"externalLink":{"type":"string","description":"External domain URL for this state","example":"example.com","maxLength":255,"nullable":true},"isActive":{"type":"boolean","description":"Whether the state is active","example":true,"default":true}}},"OpenProductResponseDto":{"type":"object","properties":{"id":{"type":"number"},"productName":{"type":"string","description":"Product name","example":"Certified Folio"},"productDescription":{"type":"string","description":"Long description of the product"},"productDescriptionForFrench":{"type":"string","description":"Long description of the product for French users"},"productDescriptionForSpanish":{"type":"string","description":"Long description of the product for Spanish users"},"upSellDescription":{"type":"string","description":"Upsell description of the product"},"upSellDescriptionForFrench":{"type":"string","description":"Upsell description of the product for French users"},"upSellDescriptionForSpanish":{"type":"string","description":"Upsell description of the product for Spanish users"},"price":{"type":"string","description":"Product price as string","example":"124.99"},"countryId":{"type":"number","description":"Country ID associated with this product price","example":1},"countryName":{"type":"string","description":"Country name associated with this product","example":"United States"},"currency":{"type":"string","description":"Currency code","example":"EUR"},"currencySymbol":{"type":"string","description":"Currency symbol","example":"€"},"productSortOrder":{"type":"string","description":"Product sort order (as string for compatibility)","example":"0"},"isPhysical":{"type":"boolean","description":"Is physical product","example":false},"isFastTrack":{"type":"boolean","description":"Is fast track product","example":false}},"required":["id","productName","productDescription","productDescriptionForFrench","productDescriptionForSpanish","upSellDescription","upSellDescriptionForFrench","upSellDescriptionForSpanish","price","countryId","countryName","currency","currencySymbol","productSortOrder","isPhysical","isFastTrack"]},"OpenProductListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/OpenProductResponseDto"}},"totalItems":{"type":"number"},"page":{"type":"number"},"size":{"type":"number"}},"required":["items","totalItems","page","size"]},"ProductCountryMappingDto":{"type":"object","properties":{"mappingId":{"type":"number","description":"Mapping ID (for updates only)"},"countryId":{"type":"number","description":"Country ID","example":1},"stateId":{"type":"number","description":"State ID","example":1},"price":{"type":"number","description":"Price must be greater than 0"}},"required":["countryId","price"]},"CreateUpdateProductDto":{"type":"object","properties":{"productName":{"type":"string","description":"Product name","example":"Product Name"},"productDescription":{"type":"string","description":"Product description","example":"Product Description","nullable":true},"productDescriptionForFrench":{"type":"string","description":"Product description for French","example":"Description du produit","nullable":true},"productDescriptionForSpanish":{"type":"string","description":"Product description for Spanish","example":"Descripción del producto","nullable":true},"upSellDescription":{"type":"string","description":"Upsell description","example":"Upsell Description","nullable":true},"upSellDescriptionForFrench":{"type":"string","description":"Upsell description for French","example":"Description de vente incitative","nullable":true},"upSellDescriptionForSpanish":{"type":"string","description":"Upsell description for Spanish","example":"Descripción de venta adicional","nullable":true},"productSortOrder":{"type":"number","description":"Product sort order (must be a positive integer starting from 1)","example":1},"isPhysical":{"type":"boolean","description":"Is physical product","example":true},"isFastTrack":{"type":"boolean","description":"Is fast track product","example":true},"isPaperCopy":{"type":"boolean","description":"Is paper copy product","example":false},"productCountryPrices":{"description":"Product country prices","example":[{"countryId":1,"stateId":1,"price":100}],"type":"array","items":{"$ref":"#/components/schemas/ProductCountryMappingDto"}}},"required":["productName","productSortOrder","isPhysical","productCountryPrices"]},"ProductCountryMappingItemDto":{"type":"object","properties":{"id":{"type":"number"},"productId":{"type":"number"},"countryId":{"type":"number"},"countryName":{"type":"string"},"currencyCode":{"type":"string"},"currencySymbol":{"type":"string"},"stateId":{"type":"number","nullable":true},"stateName":{"type":"string","nullable":true},"price":{"type":"number","nullable":true}},"required":["id","productId","countryId","countryName","currencyCode","currencySymbol"]},"ProductResponseDto":{"type":"object","properties":{"id":{"type":"number"},"productName":{"type":"string"},"productDescription":{"type":"string"},"productDescriptionForFrench":{"type":"string","nullable":true},"productDescriptionForSpanish":{"type":"string","nullable":true},"upSellDescription":{"type":"string","nullable":true},"upSellDescriptionForFrench":{"type":"string","nullable":true},"upSellDescriptionForSpanish":{"type":"string","nullable":true},"productSortOrder":{"type":"number"},"isPhysical":{"type":"boolean"},"isFastTrack":{"type":"boolean"},"isPaperCopy":{"type":"boolean"},"productCountryPrices":{"type":"array","items":{"$ref":"#/components/schemas/ProductCountryMappingItemDto"}}},"required":["id","productName","productSortOrder","isPhysical","isFastTrack","isPaperCopy","productCountryPrices"]},"OrderProductDto":{"type":"object","properties":{"productId":{"type":"number","description":"Product ID","example":1}},"required":["productId"]},"CreateUpdateOrderDto":{"type":"object","properties":{"titleNumber":{"type":"string","description":"Title number","example":"TN123456"},"instrumentCopyNumber":{"type":"string","description":"Instrument copy number","example":"IC123456"},"customerEmail":{"type":"string","description":"Customer email","example":"customer@example.com"},"customerId":{"type":"number","description":"Customer ID","example":1},"tenure":{"type":"string","description":"Tenure type","example":"Freehold"},"address1":{"type":"string","description":"Address line 1","example":"123 Main Street"},"flatUnit":{"type":"string","description":"Flat/Unit","example":"Flat 5B"},"municipality":{"type":"string","description":"Municipality","example":"Madrid"},"registry":{"type":"string","description":"Registry","example":"Registro de la Propiedad"},"cruIdufir":{"type":"string","description":"CRU / IDUFIR","example":"1234567890"},"identificationType":{"type":"string","description":"Identification type","enum":["None","NIE","NIF"],"example":"None"},"identificationNumber":{"type":"string","description":"Identification number (required when identification type is NIE or NIF)","example":"X1234567L"},"nameAsPerIdentification":{"type":"string","description":"Name as per identification (required when identification type is NIE or NIF)","example":"John Doe"},"city":{"type":"string","description":"City","example":"London"},"suburb":{"type":"string","description":"Suburb","example":"Ponsonby"},"county":{"type":"string","description":"County","example":"Greater London"},"postCode":{"type":"string","description":"Post code","example":"SW1A 1AA"},"country":{"type":"string","description":"Country","example":"United Kingdom"},"state":{"type":"string","description":"State","example":"England"},"currency":{"type":"string","description":"Currency code","example":"GBP"},"totalAmount":{"type":"number","description":"Total order amount","example":199.99},"orderStatusId":{"type":"number","description":"Order status ID","example":1},"products":{"description":"Products in the order (only productId required)","example":[{"productId":1},{"productId":2}],"type":"array","items":{"$ref":"#/components/schemas/OrderProductDto"}},"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"456 Delivery Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Apartment 5B"},"shippingCity":{"type":"string","description":"Shipping city","example":"Manchester"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"M1 1AA"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater Manchester"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+44 123 456 7890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"John"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Doe"},"updateItWithAllLinkedOrders":{"type":"boolean","description":"Update shipping address for all linked orders","example":false},"isExpressDelivery":{"type":"boolean","description":"Is express delivery","example":false},"isRequestedPaperCopy":{"type":"boolean","description":"Customer requested paper copy (overrides product-derived flag)","example":false},"utmCampaign":{"type":"string","description":"UTM Campaign","example":"summer_sale"},"utmTerm":{"type":"string","description":"UTM Term","example":"land_registry"},"utmContent":{"type":"string","description":"UTM Content","example":"banner_ad"},"utmSource":{"type":"string","description":"UTM Source","example":"google"},"utmMedium":{"type":"string","description":"UTM Medium","example":"cpc"},"hasSwimmingPool":{"type":"boolean","description":"Whether the property has a swimming pool","example":false},"orderLng":{"type":"string","description":"Order language","enum":["en","fr","es"],"example":"en"}},"required":["customerId","products"]},"OrderCreateUpdateResponseDto":{"type":"object","properties":{"orderId":{"type":"number","description":"Order ID","example":1},"customerEmail":{"type":"string","description":"Customer email","example":"customer@example.com"},"emailValid":{"type":"boolean","description":"Email valid","example":true},"emailValidationStatus":{"type":"string","description":"Email validation status (UNKNOWN, VALID, INVALID)","example":"UNKNOWN"},"isNewCustomer":{"type":"boolean","description":"True if customer was auto-created during this order","example":true},"documentAccessLink":{"type":"string","description":"Permanent document access link","example":"https://api.example.com/orders/track/abc-123-xyz"}},"required":["orderId","customerEmail","emailValid"]},"CreateUpSellOrderDto":{"type":"object","properties":{"parentOrderId":{"type":"number","description":"Parent order ID to fetch customer and shipping details","example":123},"productIds":{"description":"Array of product IDs to purchase as upsell","example":[2,3,5],"minItems":1,"type":"array","items":{"type":"number"}},"upSellSource":{"type":"string","description":"Source of the upsell order","enum":["ORDER","EMAIL","ADMIN","Document Link"],"example":"ORDER","default":"ORDER"},"orderLng":{"type":"string","description":"Order language","enum":["en","fr","es"],"example":"en"},"suburb":{"type":"string","description":"Property suburb","example":"Ponsonby"},"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"221B Baker Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Marylebone"},"shippingCity":{"type":"string","description":"Shipping city","example":"London"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"NW1 6XE"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater London"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+441234567890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"Sherlock"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Holmes"},"hasSwimmingPool":{"type":"boolean","description":"Whether property has a swimming pool","example":true},"instrumentCopyNumber":{"type":"string","description":"Instrument copy number (optional)","example":"123456789"}},"required":["parentOrderId","productIds"]},"OrderStatusInfoDto":{"type":"object","properties":{"id":{"type":"number","description":"Order status ID","example":1},"status":{"type":"string","description":"Order status name","example":"Processing"},"backgroundColor":{"type":"string","description":"Background color","example":"#FF5733"},"textColor":{"type":"string","description":"Text color","example":"#FFFFFF"},"borderColor":{"type":"string","description":"Border color","example":"#000000"}},"required":["id","status"]},"OrderListItemDto":{"type":"object","properties":{"id":{"type":"number","description":"Order ID","example":1},"titleNumber":{"type":"string","description":"Title number","example":"TN123456"},"instrumentCopyNumber":{"type":"string","description":"Instrument copy number","example":"IC123456"},"customerEmail":{"type":"string","description":"Customer email","example":"customer@example.com"},"customerId":{"type":"number","description":"Customer ID","example":1},"tenure":{"type":"string","description":"Tenure type","example":"Freehold"},"address1":{"type":"string","description":"Address line 1","example":"123 Main Street"},"flatUnit":{"type":"string","description":"Flat/Unit","example":"Flat 5B"},"municipality":{"type":"string","description":"Municipality","example":"Madrid"},"registry":{"type":"string","description":"Registry","example":"Registro de la Propiedad"},"cruIdufir":{"type":"string","description":"CRU / IDUFIR","example":"1234567890"},"identificationType":{"type":"string","description":"Identification type","example":"NIE"},"identificationNumber":{"type":"string","description":"Identification number","example":"X1234567L"},"nameAsPerIdentification":{"type":"string","description":"Name as per identification","example":"John Doe"},"city":{"type":"string","description":"City","example":"London"},"suburb":{"type":"string","description":"Suburb","example":"Ponsonby"},"county":{"type":"string","description":"County","example":"Greater London"},"country":{"type":"string","description":"Country","example":"United Kingdom"},"countryId":{"type":"number","description":"Country ID","example":1},"stateId":{"type":"number","description":"State ID","example":1},"currency":{"type":"string","description":"Currency code","example":"GBP"},"currencySymbol":{"type":"string","description":"Currency symbol","example":"£"},"totalAmount":{"type":"number","description":"Total order amount","example":199.99},"orderStatus":{"description":"Order status information","allOf":[{"$ref":"#/components/schemas/OrderStatusInfoDto"}]},"orderDateTime":{"format":"date-time","type":"string","description":"Order date time"},"isExpressDelivery":{"type":"boolean","description":"Is express delivery","example":false},"isRequestedPaperCopy":{"type":"boolean","description":"Customer requested paper copy","example":false},"customerOrderCount":{"type":"number","description":"Total number of orders by this customer","example":5},"postCode":{"type":"string","description":"Post code","example":"SW1A 1AA"},"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"456 Delivery Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Apartment 5B"},"shippingCity":{"type":"string","description":"Shipping city","example":"Manchester"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"M1 1AA"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater Manchester"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+44 123 456 7890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"John"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Doe"},"postCodeOrderCount":{"type":"number","description":"Total number of orders with the same post code","example":3},"paymentMethod":{"type":"string","description":"Payment method used","example":"card"},"latestEmailStatus":{"type":"string","description":"Latest email status for this order","example":"delivered"},"customerIsVerified":{"type":"boolean","description":"Whether the customer email is verified","example":true},"customerEmailValidationStatus":{"type":"string","description":"Customer email validation status (UNKNOWN, VALID, INVALID)","example":"UNKNOWN"},"orderLng":{"type":"string","description":"Order language","example":"en"},"ghostOrderId":{"type":"number","description":"Ghost order ID associated with this order","example":2},"createdAt":{"format":"date-time","type":"string","description":"Created at timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Updated at timestamp"},"isCertified":{"type":"boolean","description":"Whether the order contains certified products","example":true},"applicationNumber":{"type":"string","description":"Land registry application number (set via send-email when certified; not shown in email body)","example":"APP-12345","nullable":true},"upSellSource":{"type":"string","description":"Source of upsell order (ORDER=from order page, EMAIL=from email)","example":"EMAIL","enum":["ORDER","EMAIL"]},"upSellEntryChannel":{"type":"string","description":"How the customer reached the tracking page before buying (Document Link upsells)","example":"DOCUMENT_REMINDER_EMAIL"},"upSellAttribution":{"type":"object","description":"Extra attribution detail for Document Link upsells (reminder day/time/tz, email type, etc.)"},"utmSource":{"type":"string","description":"UTM Source","example":"google"},"refundedAmount":{"type":"number","description":"Total refunded amount","example":50},"refundDateTime":{"format":"date-time","type":"string","description":"Refund date time"},"products":{"description":"Products in the order","type":"array","items":{"type":"object"}},"stopAbandonmentEmails":{"type":"boolean","description":"Whether abandonment emails are stopped for this order","example":false},"isAbandonmentRecovered":{"type":"boolean","description":"Whether this order was successfully paid after an abandonment email was sent","example":false},"hasSwimmingPool":{"type":"boolean","description":"Whether the property has a swimming pool","example":false}},"required":["id","customerId","totalAmount","orderStatus","isExpressDelivery","isRequestedPaperCopy","customerOrderCount","createdAt","updatedAt","refundedAmount","products","stopAbandonmentEmails","isAbandonmentRecovered","hasSwimmingPool"]},"FindAllOrdersResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of orders"},"items":{"description":"List of orders","type":"array","items":{"$ref":"#/components/schemas/OrderListItemDto"}},"page":{"type":"number","description":"Current page number"},"size":{"type":"number","description":"Number of items per page"}},"required":["totalItems","items","page","size"]},"OrderHistoryResponseDto":{"type":"object","properties":{"totalOrders":{"type":"number","description":"Total number of orders for the customer","example":5},"orders":{"description":"List of orders","type":"array","items":{"$ref":"#/components/schemas/OrderListItemDto"}},"page":{"type":"number","description":"Current page number"},"size":{"type":"number","description":"Number of items per page"}},"required":["totalOrders","orders","page","size"]},"UpdateOrderEmailDto":{"type":"object","properties":{"orderId":{"type":"number","description":"Order ID to update","example":123},"newEmail":{"type":"string","description":"New email address for the order","example":"newemail@example.com"},"isAll":{"type":"boolean","description":"Update all orders with the same email as the specified order. If true, all orders with matching email will be updated.","example":false,"default":false}},"required":["orderId","newEmail"]},"OrderProductResponseDto":{"type":"object","properties":{"productId":{"type":"number","description":"Product ID","example":1},"productName":{"type":"string","description":"Product name","example":"Land Registry Document"},"price":{"type":"number","description":"Product price","example":99.99}},"required":["productId","productName","price"]},"OrderDetailsPaymentDto":{"type":"object","properties":{"id":{"type":"number","description":"Payment ID"},"paymentProvider":{"type":"string","description":"Payment provider (stripe, paypal, etc.)"},"amount":{"type":"number","description":"Payment amount"},"currency":{"type":"string","description":"Payment currency"},"status":{"type":"string","description":"Payment status"},"paymentSource":{"type":"string","description":"Payment method/source"},"billingEmail":{"type":"string","description":"Billing email captured by payment gateway","example":"customer@example.com"},"transactionPaymentId":{"type":"string","description":"Gateway transaction/payment identifier (e.g. Stripe PaymentIntent ID pi_...)","example":"pi_1234567890"},"transactionDashboardUrl":{"type":"string","description":"Full URL to view this transaction in the payment gateway dashboard","example":"https://dashboard.stripe.com/test/payments/pi_1234567890"},"paymentMethod":{"type":"string","description":"User-friendly payment method name","example":"Credit Card"},"paymentOrigin":{"type":"string","description":"Payment origin"},"cardBrand":{"type":"string","description":"Card brand (visa, mastercard, etc.)"},"cardLast4":{"type":"string","description":"Last 4 digits of card"},"createdAt":{"format":"date-time","type":"string","description":"Payment creation timestamp"}},"required":["id","paymentProvider","amount","currency","status","createdAt"]},"OrderRefundRecordDto":{"type":"object","properties":{"id":{"type":"number","description":"Refund record ID"},"amount":{"type":"number","description":"Amount refunded in this action","example":25},"method":{"type":"string","enum":["manual","gateway","dispute"],"description":"manual = admin manually refunded; gateway = via payment provider","example":"manual"},"reason":{"type":"string","description":"Reason given for this refund"},"performedByUserId":{"type":"number","description":"User ID who performed the refund"},"performedByName":{"type":"string","description":"Full name of the user who performed the refund"},"source":{"type":"string","enum":["admin_panel","webhook"],"description":"admin_panel = triggered from dashboard; webhook = from gateway","example":"admin_panel"},"isFullRefund":{"type":"boolean","description":"Was the order fully refunded after this action?"},"totalRefundedAfter":{"type":"number","description":"Business-visible total refunded amount on the order after this action","example":50},"remainingAfter":{"type":"number","description":"Remaining refundable amount after this action","example":50},"currency":{"type":"string","description":"Currency code","example":"GBP"},"gatewayRefundId":{"type":"string","description":"Gateway-assigned refund ID"},"createdAt":{"format":"date-time","type":"string","description":"When this refund was recorded"}},"required":["id","amount","method","source","isFullRefund","totalRefundedAfter","createdAt"]},"OrderRefundSummaryDto":{"type":"object","properties":{"totalCount":{"type":"number","description":"Total number of refund actions on this order"},"manualCount":{"type":"number","description":"Number of manual refunds"},"gatewayCount":{"type":"number","description":"Number of gateway refunds"},"disputeCount":{"type":"number","description":"Number of dispute records"}},"required":["totalCount","manualCount","gatewayCount"]},"OrderDetailsResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Order ID","example":1},"titleNumber":{"type":"string","description":"Title number","example":"TN123456"},"instrumentCopyNumber":{"type":"string","description":"Instrument copy number","example":"IC123456"},"customerEmail":{"type":"string","description":"Customer email","example":"customer@example.com"},"customerId":{"type":"number","description":"Customer ID","example":1},"emailValid":{"type":"boolean","description":"Email valid","example":true},"tenure":{"type":"string","description":"Tenure type","example":"Freehold"},"refundReason":{"type":"string","description":"Refund reason","example":"Customer requested refund"},"refundedAmount":{"type":"number","description":"Total refunded amount","example":50},"refundDateTime":{"format":"date-time","type":"string","description":"Refund date time"},"address1":{"type":"string","description":"Address line 1","example":"123 Main Street"},"flatUnit":{"type":"string","description":"Flat/Unit","example":"Flat 5B"},"municipality":{"type":"string","description":"Municipality","example":"Madrid"},"registry":{"type":"string","description":"Registry","example":"Registro de la Propiedad"},"cruIdufir":{"type":"string","description":"CRU / IDUFIR","example":"1234567890"},"identificationType":{"type":"string","description":"Identification type","example":"NIE"},"identificationNumber":{"type":"string","description":"Identification number","example":"X1234567L"},"nameAsPerIdentification":{"type":"string","description":"Name as per identification","example":"John Doe"},"city":{"type":"string","description":"City","example":"London"},"suburb":{"type":"string","description":"Suburb","example":"Ponsonby"},"county":{"type":"string","description":"County","example":"Greater London"},"postCode":{"type":"string","description":"Post code","example":"SW1A 1AA"},"country":{"type":"string","description":"Country","example":"United Kingdom"},"countryId":{"type":"number","description":"Country ID","example":1},"stateId":{"type":"number","description":"State ID","example":1},"stateName":{"type":"string","description":"State Name","example":"England"},"currency":{"type":"string","description":"Currency code","example":"GBP"},"currencySymbol":{"type":"string","description":"Currency symbol","example":"£"},"totalAmount":{"type":"number","description":"Total order amount","example":199.99},"orderStatus":{"description":"Order status information","allOf":[{"$ref":"#/components/schemas/OrderStatusInfoDto"}]},"orderDateTime":{"format":"date-time","type":"string","description":"Order date time"},"products":{"description":"Products in the order","type":"array","items":{"$ref":"#/components/schemas/OrderProductResponseDto"}},"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"456 Delivery Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Apartment 5B"},"shippingCity":{"type":"string","description":"Shipping city","example":"Manchester"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"M1 1AA"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater Manchester"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+44 123 456 7890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"John"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Doe"},"isExpressDelivery":{"type":"boolean","description":"Is express delivery","example":false},"isRequestedPaperCopy":{"type":"boolean","description":"Customer requested paper copy","example":false},"utmCampaign":{"type":"string","description":"UTM Campaign","example":"summer_sale"},"utmTerm":{"type":"string","description":"UTM Term","example":"land_registry"},"utmContent":{"type":"string","description":"UTM Content","example":"banner_ad"},"utmSource":{"type":"string","description":"UTM Source","example":"google"},"utmMedium":{"type":"string","description":"UTM Medium","example":"cpc"},"orderLng":{"type":"string","description":"Order language","example":"en"},"paymentMethod":{"type":"string","description":"Payment method used","example":"Credit Card"},"ghostOrderId":{"type":"number","description":"Ghost order ID associated with this order","example":2},"childOrderIds":{"description":"All descendant order IDs (full subtree, including nested upsells), excluding orders in System Generated status","example":[11,15],"type":"array","items":{"type":"number"}},"createdAt":{"format":"date-time","type":"string","description":"Created at timestamp"},"updatedAt":{"format":"date-time","type":"string","description":"Updated at timestamp"},"documentAccessLink":{"type":"string","description":"Permanent document access link","example":"https://api.example.com/orders/track/abc-123-xyz"},"isCertified":{"type":"boolean","description":"Whether the order contains certified products","example":true},"applicationNumber":{"type":"string","description":"Land registry application number (set via send-email when certified; not shown in email body)","example":"APP-12345","nullable":true},"upSellSource":{"type":"string","description":"Source of upsell order (ORDER=from order page, EMAIL=from email)","example":"EMAIL","enum":["ORDER","EMAIL"]},"upSellEntryChannel":{"type":"string","description":"How the customer reached the tracking page before buying (Document Link upsells)","example":"DOCUMENT_REMINDER_EMAIL"},"upSellAttribution":{"type":"object","description":"Extra attribution detail for Document Link upsells (reminder day/time/tz, email type, etc.)"},"parentOrderId":{"type":"number","description":"Parent order ID if this is an upsell","example":1},"stopAbandonmentEmails":{"type":"boolean","description":"Whether abandonment emails are stopped for this order","example":false},"isAbandonmentRecovered":{"type":"boolean","description":"Whether this order was successfully paid after an abandonment email was sent","example":false},"hasSwimmingPool":{"type":"boolean","description":"Whether the property has a swimming pool","example":false},"trackingLink":{"type":"string","description":"Tracking link for the order","example":"https://api.example.com/orders/track/abc-123-xyz"},"documentLinkValidUntil":{"format":"date-time","type":"string","description":"Extended document link validity (UTC). Null when only the default tracking expiry window applies.","example":"2027-07-20T10:00:00.000Z"},"draftEmailAttachments":{"type":"array","description":"Draft email attachments staged for this order. Only returned when the request is authenticated (admin/employee). Cleared automatically when the email is sent.","items":{"type":"object","properties":{"filename":{"type":"string"},"url":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"number","nullable":true}}}},"billingEmail":{"type":"string","description":"Billing email for root summary: latest attempt for Stripe/PayPal; for Revolut, earliest successful attempt when multiple rows exist.","example":"customer@example.com"},"transactionPaymentId":{"type":"string","description":"Gateway transaction id for root summary: latest attempt for Stripe/PayPal; for Revolut, earliest successful attempt.","example":"pi_1234567890"},"transactionDashboardUrl":{"type":"string","description":"Dashboard URL for root summary: latest attempt for Stripe/PayPal; for Revolut, earliest successful attempt.","example":"https://dashboard.stripe.com/test/payments/pi_1234567890"},"payments":{"description":"Payment details for the order","type":"array","items":{"$ref":"#/components/schemas/OrderDetailsPaymentDto"}},"refundHistory":{"description":"Full refund history for this order, newest first","type":"array","items":{"$ref":"#/components/schemas/OrderRefundRecordDto"}},"refundSummary":{"description":"Refund counts summary for this order","allOf":[{"$ref":"#/components/schemas/OrderRefundSummaryDto"}]}},"required":["id","customerId","refundedAmount","totalAmount","orderStatus","products","isExpressDelivery","isRequestedPaperCopy","createdAt","updatedAt","stopAbandonmentEmails","isAbandonmentRecovered","hasSwimmingPool","payments"]},"OrderDetailsActivityLogDto":{"type":"object","properties":{"id":{"type":"number","description":"Activity log ID"},"title":{"type":"string","description":"Activity title"},"description":{"type":"string","description":"Activity description"},"action":{"type":"string","enum":["CREATE","UPDATE","DELETE","LOGIN","LOGOUT","VIEW","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELED","PAYMENT_PROCESSING","EMAIL_SENT","DOCUMENT_VIEW","DOCUMENT_DOWNLOAD","OTHER"],"description":"Activity action type"},"userName":{"type":"string","description":"User who performed the action"},"source":{"type":"string","enum":["APPLICATION","WEBSITE"],"description":"Activity source"},"metadata":{"type":"object","description":"Activity metadata"},"createdAt":{"format":"date-time","type":"string","description":"Activity timestamp"}},"required":["id","title","action","createdAt"]},"OrderActivityLogPerformerPartitionDto":{"type":"object","properties":{"performer":{"type":"string","description":"Display name of who performed the actions in this partition","example":"John Doe"},"userId":{"type":"number","description":"Staff user ID when the performer is a logged-in user","example":12},"logs":{"description":"Activity logs for this performer, newest first","type":"array","items":{"$ref":"#/components/schemas/OrderDetailsActivityLogDto"}}},"required":["performer","logs"]},"OrderActivityLogsByPerformerResponseDto":{"type":"object","properties":{"totalLogs":{"type":"number","description":"Total activity log count across all partitions","example":15},"partitions":{"description":"Activity logs grouped by performer, partitions ordered by most recent activity","type":"array","items":{"$ref":"#/components/schemas/OrderActivityLogPerformerPartitionDto"}}},"required":["totalLogs","partitions"]},"UpdateMultipleOrderStatusDto":{"type":"object","properties":{"orderIds":{"description":"List of order IDs to update","example":[101,102,103],"maxItems":500,"type":"array","items":{"type":"number"}},"orderStatusId":{"type":"number","description":"Target order status ID","example":3}},"required":["orderIds","orderStatusId"]},"SkippedOrderStatusUpdateDto":{"type":"object","properties":{"id":{"type":"number","description":"Order ID","example":22},"reason":{"type":"string","description":"Reason why the order was skipped","example":"Already in selected status"}},"required":["id","reason"]},"UpdateMultipleOrderStatusResponseDto":{"type":"object","properties":{"targetStatusId":{"type":"number","description":"Requested order status ID","example":3},"targetStatusName":{"type":"string","description":"Requested order status name","example":"Dispatched"},"requestedCount":{"type":"number","description":"Total valid unique order IDs received in request","example":3},"updatedCount":{"type":"number","description":"Number of orders updated","example":2},"skippedCount":{"type":"number","description":"Number of orders skipped because status was already same","example":1},"updatedOrderIds":{"description":"IDs of orders that were updated","example":[21,23],"type":"array","items":{"type":"number"}},"skippedOrders":{"description":"Skipped orders with reason","type":"array","items":{"$ref":"#/components/schemas/SkippedOrderStatusUpdateDto"}}},"required":["targetStatusId","targetStatusName","requestedCount","updatedCount","skippedCount","updatedOrderIds","skippedOrders"]},"UpdateOrderShippingAddressDto":{"type":"object","properties":{"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"456 Delivery Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Apartment 5B"},"shippingCity":{"type":"string","description":"Shipping city","example":"Manchester"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"M1 1AA"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater Manchester"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+44 123 456 7890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"John"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Doe"},"updateItWithAllLinkedOrders":{"type":"boolean","description":"Update shipping address for all linked orders","example":false}}},"UpdateOrderDto":{"type":"object","properties":{"orderStatusId":{"type":"number","description":"Order status ID","example":1},"orderDateTime":{"type":"string","description":"Order date time (ISO 8601 format)","example":"2024-01-15T10:30:00.000Z"},"address1":{"type":"string","description":"Address line 1","example":"123 Main Street"},"flatUnit":{"type":"string","description":"Flat/Unit","example":"Flat 5B"},"municipality":{"type":"string","description":"Municipality","example":"Madrid"},"registry":{"type":"string","description":"Registry","example":"Registro de la Propiedad"},"cruIdufir":{"type":"string","description":"CRU / IDUFIR","example":"1234567890"},"identificationType":{"type":"string","description":"Identification type","enum":["None","NIE","NIF"],"example":"None"},"identificationNumber":{"type":"string","description":"Identification number (required when identification type is NIE or NIF)","example":"X1234567L"},"nameAsPerIdentification":{"type":"string","description":"Name as per identification (required when identification type is NIE or NIF)","example":"John Doe"},"city":{"type":"string","description":"City","example":"London"},"suburb":{"type":"string","description":"Suburb","example":"Ponsonby"},"county":{"type":"string","description":"County","example":"Greater London"},"postCode":{"type":"string","description":"Post code","example":"SW1A 1AA"},"country":{"type":"string","description":"Country","example":"United Kingdom"},"state":{"type":"string","description":"State","example":"England"},"shippingAddress1":{"type":"string","description":"Shipping address line 1","example":"456 Delivery Street"},"shippingAddress2":{"type":"string","description":"Shipping address line 2","example":"Apartment 5B"},"shippingCity":{"type":"string","description":"Shipping city","example":"Manchester"},"shippingPostcode":{"type":"string","description":"Shipping postcode","example":"M1 1AA"},"shippingCounty":{"type":"string","description":"Shipping county","example":"Greater Manchester"},"shippingPhone":{"type":"string","description":"Shipping phone number","example":"+44 123 456 7890"},"shippingFirstName":{"type":"string","description":"Shipping first name","example":"John"},"shippingLastName":{"type":"string","description":"Shipping last name","example":"Doe"},"updateItWithAllLinkedOrders":{"type":"boolean","description":"Update shipping address for all linked orders","example":false},"hasSwimmingPool":{"type":"boolean","description":"Whether the property has a swimming pool","example":false},"instrumentCopyNumber":{"type":"string","description":"Instrument copy number","example":"IC123456"},"orderLng":{"type":"string","description":"Order language","enum":["en","fr","es"],"example":"en"}}},"ExtendDocumentLinkValidityDto":{"type":"object","properties":{"durationValue":{"type":"number","description":"How long to extend the document link validity","example":30},"durationUnit":{"type":"string","description":"Unit for the extension duration","enum":["day","month","year"],"example":"day"},"reason":{"type":"string","description":"Optional reason for the extension","example":"Customer requested additional access time"}},"required":["durationValue","durationUnit"]},"RefundOrderDto":{"type":"object","properties":{"refundAmount":{"type":"number","description":"Amount to refund (if not provided or 0, full refund will be processed)","example":50},"isManualRefund":{"type":"boolean","description":"Set true to process manual refund (skip gateway API and send customer refund email immediately)","example":false},"refundReason":{"type":"string","description":"Reason for refund","example":"Customer requested refund due to product issue"}},"required":["refundReason"]},"AddOrderNoteDto":{"type":"object","properties":{"note":{"type":"string","description":"Note to add to the order","example":"Customer requested expedited shipping"}},"required":["note"]},"SendOrderEmailDto":{"type":"object","properties":{"subject":{"type":"string","description":"Custom subject for the email","example":"Your Order Confirmation"},"body":{"type":"string","description":"Custom body for the email (HTML supported). Use {{DOCUMENT_LINK}} for the document access button. Use {{UPSELL_LINK}} or {{upsellLink}} for the upsell checkout button when upSell product IDs are provided; if omitted, the upsell button is inserted after \"link below\" or appended to the body.","example":"<p>Hello {{customerName}}, your order is being processed.</p><p>Access your documents:</p>{{DOCUMENT_LINK}}<p>{{UPSELL_LINK}}</p>"},"upSell":{"description":"Array of product IDs for upselling","example":[1,2],"type":"array","items":{"type":"number"}},"isPostage":{"type":"boolean","description":"When true and email is sent successfully, order status will be updated to Postage.","example":true},"applicationNumber":{"type":"string","description":"Certified orders only when non-empty. Omit to leave unchanged; null clears the stored value.","example":"APP-12345","nullable":true}}},"ToggleAbandonmentEmailsDto":{"type":"object","properties":{"stop":{"type":"boolean","description":"Whether to stop or resume abandonment emails","example":true,"default":false}},"required":["stop"]},"TrackingPageUpsellDto":{"type":"object","properties":{"productIds":{"type":"object","description":"Selected product id(s) for Document Link upsell"},"upsell_entry":{"type":"string","example":"document_reminder"},"upsell_email_type":{"type":"string","example":"document-reminder"},"reminder_stage":{"type":"string","example":"1"},"reminder_day":{"type":"string","example":"7d"},"tz":{"type":"string","example":"Europe/London"},"local_time":{"type":"string","example":"10:00:00"}}},"CreateUpdateOrderStatusDto":{"type":"object","properties":{"status":{"type":"string","description":"Order status name","example":"Pending","maxLength":255},"backgroundColor":{"type":"string","description":"Background color for the status (hex color code)","example":"#FF5733","maxLength":50},"textColor":{"type":"string","description":"Text color for the status (hex color code)","example":"#FFFFFF","maxLength":50},"borderColor":{"type":"string","description":"Border color for the status (hex color code)","example":"#000000","maxLength":50},"isSystemDefined":{"type":"boolean","description":"Whether this status is system defined","example":false,"default":false}},"required":["status"]},"OrderStatusResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Order status ID","example":1},"status":{"type":"string","description":"Order status name","example":"Pending"},"backgroundColor":{"type":"string","description":"Background color for the status","example":"#FF5733"},"textColor":{"type":"string","description":"Text color for the status","example":"#FFFFFF"},"borderColor":{"type":"string","description":"Border color for the status","example":"#000000"},"isSystemDefined":{"type":"boolean","description":"Whether this status is system defined","example":false},"createdByName":{"type":"string","description":"Created by user name","example":"John Doe"}},"required":["id","status","isSystemDefined"]},"OrderStatusListResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items","example":100},"items":{"description":"List of order statuses","type":"array","items":{"$ref":"#/components/schemas/OrderStatusResponseDto"}},"page":{"type":"number","description":"Current page number","example":0},"size":{"type":"number","description":"Number of items per page","example":10}},"required":["totalItems","items","page","size"]},"TransferOrdersDto":{"type":"object","properties":{"fromStatusId":{"type":"number","description":"Source order status ID (orders with this status will be transferred)","example":1},"toStatusId":{"type":"number","description":"Target order status ID (orders will be transferred to this status)","example":2}},"required":["fromStatusId","toStatusId"]},"SendEmailDto":{"type":"object","properties":{"to":{"type":"string","description":"Recipient email address","example":"user@example.com"},"subject":{"type":"string","description":"Email subject","example":"Welcome to Land Registry"},"recipientName":{"type":"string","description":"Recipient name","example":"John Doe"},"htmlContent":{"type":"string","description":"HTML body content","example":"<p>Welcome to our platform</p>"},"templateType":{"type":"string","description":"Email template type","enum":["order-confirmation","password-reset","verification"],"default":"order-confirmation"},"orderId":{"type":"number","description":"Related order ID for tracking","example":1},"customerId":{"type":"number","description":"Related customer ID for tracking","example":1},"metadata":{"type":"object","description":"Additional metadata to store with the email log","example":{"orderNumber":"ORD-2025-001","invoiceId":123,"productName":"Land Registry Service"}},"files":{"description":"Array of files to attach (optional)","type":"array","items":{"type":"string","format":"binary"}}},"required":["to","subject","recipientName"]},"EmailLogListItemDto":{"type":"object","properties":{"id":{"type":"number"},"messageId":{"type":"string"},"recipient":{"type":"string"},"sender":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["Sent","Processed","Delivered","Opened","Clicked","Bounced","Deferred","Dropped","Spam Complaint","Spam Report","Unsubscribed","Group Unsubscribe","Group Resubscribe","Subscription Change","Failed"]},"sentAt":{"format":"date-time","type":"string"},"customerOrderCount":{"type":"number"},"attachments":{"type":"array","items":{"type":"string"}},"attachmentsCount":{"type":"number"},"opens":{"type":"number","description":"Number of times email was opened"},"clicks":{"type":"number","description":"Number of times links were clicked"},"isOpened":{"type":"boolean","description":"Whether email was opened at least once"},"isClicked":{"type":"boolean","description":"Whether links were clicked at least once"},"clickedLink":{"type":"string","description":"The URL that was clicked"},"createdAt":{"format":"date-time","type":"string"},"webhookResponse":{"type":"string"},"ipAddress":{"type":"string"},"browser":{"type":"string"},"location":{"type":"string"},"history":{"type":"array","items":{"$ref":"#/components/schemas/EmailLogListItemDto"}}},"required":["id","messageId","recipient","sender","subject","status","sentAt","createdAt"]},"EmailLogListResponseDto":{"type":"object","properties":{"totalItems":{"type":"number"},"items":{"type":"array","items":{"$ref":"#/components/schemas/EmailLogListItemDto"}},"page":{"type":"number"},"size":{"type":"number"}},"required":["totalItems","items","page","size"]},"DeleteEmailLogAttachmentDto":{"type":"object","properties":{"emailLogId":{"type":"number","description":"Email log row id (same as the id in GET /email-logs list / GET /email-logs/:id).","example":75272},"url":{"type":"string","description":"Full URL of the attachment to remove (must match the url returned on email log items)","example":"https://s3.eu-west-2.amazonaws.com/staging.example.org/uploads/abc.pdf"}},"required":["emailLogId","url"]},"EmailLogDetailsResponseDto":{"type":"object","properties":{"id":{"type":"number"},"messageId":{"type":"string"},"recipient":{"type":"string"},"sender":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["Sent","Processed","Delivered","Opened","Clicked","Bounced","Deferred","Dropped","Spam Complaint","Spam Report","Unsubscribed","Group Unsubscribe","Group Resubscribe","Subscription Change","Failed"]},"sentAt":{"format":"date-time","type":"string"},"customerOrderCount":{"type":"number"},"attachments":{"type":"array","items":{"type":"string"}},"attachmentsCount":{"type":"number"},"opens":{"type":"number","description":"Number of times email was opened"},"clicks":{"type":"number","description":"Number of times links were clicked"},"isOpened":{"type":"boolean","description":"Whether email was opened at least once"},"isClicked":{"type":"boolean","description":"Whether links were clicked at least once"},"clickedLink":{"type":"string","description":"The URL that was clicked"},"createdAt":{"format":"date-time","type":"string"},"webhookResponse":{"type":"string"},"ipAddress":{"type":"string"},"browser":{"type":"string"},"location":{"type":"string"},"history":{"type":"array","items":{"$ref":"#/components/schemas/EmailLogListItemDto"}},"orderId":{"type":"number"},"customerId":{"type":"number"},"emailTemplate":{"type":"string"},"content":{"type":"string"},"metadata":{"type":"object"},"deliveredAt":{"format":"date-time","type":"string"},"openedAt":{"format":"date-time","type":"string"},"clickedAt":{"format":"date-time","type":"string"},"bouncedAt":{"format":"date-time","type":"string"},"provider":{"type":"string"}},"required":["id","messageId","recipient","sender","subject","status","sentAt","createdAt"]},"ActivityLogResponseDto":{"type":"object","properties":{"id":{"type":"number","example":1},"title":{"type":"string","example":"Order Created"},"description":{"type":"string","example":"User john@example.com created order #1234"},"action":{"type":"string","enum":["CREATE","UPDATE","DELETE","LOGIN","LOGOUT","VIEW","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELED","PAYMENT_PROCESSING","EMAIL_SENT","DOCUMENT_VIEW","DOCUMENT_DOWNLOAD","OTHER"],"example":"CREATE"},"module":{"type":"string","example":"orders"},"userId":{"type":"string","example":"1"},"userEmail":{"type":"string","example":"john@example.com"},"userName":{"type":"string","example":"John Doe"},"ipAddress":{"type":"string","example":"192.168.1.1"},"browser":{"type":"string","example":"Chrome"},"location":{"type":"string","example":"New York, United States"},"entityId":{"type":"number","example":1234},"entityType":{"type":"string","example":"Order"},"paymentId":{"type":"number","example":5678},"source":{"type":"string","enum":["APPLICATION","WEBSITE"],"example":"APPLICATION"},"metadata":{"type":"object","example":{"browser":"Chrome","browserVersion":"120.0","os":"Windows","osVersion":"10/11","deviceType":"Desktop","language":"en-US"}},"createdAt":{"format":"date-time","type":"string","example":"2024-01-15T10:30:00.000Z"}},"required":["id","title","action","module","createdAt"]},"FindAllActivityLogsResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","example":100},"items":{"type":"array","items":{"$ref":"#/components/schemas/ActivityLogResponseDto"}},"page":{"type":"number","example":0},"size":{"type":"number","example":10}},"required":["totalItems","items","page","size"]},"ActivityLogDetailResponseDto":{"type":"object","properties":{"id":{"type":"number","example":1},"title":{"type":"string","example":"Order Created"},"description":{"type":"string","example":"User john@example.com created order #1234"},"action":{"type":"string","enum":["CREATE","UPDATE","DELETE","LOGIN","LOGOUT","VIEW","PAYMENT_SUCCESS","PAYMENT_FAILED","PAYMENT_CANCELED","PAYMENT_PROCESSING","EMAIL_SENT","DOCUMENT_VIEW","DOCUMENT_DOWNLOAD","OTHER"],"example":"CREATE"},"module":{"type":"string","example":"orders"},"userId":{"type":"string","example":"1"},"userEmail":{"type":"string","example":"john@example.com"},"userName":{"type":"string","example":"John Doe"},"ipAddress":{"type":"string","example":"192.168.1.1"},"browser":{"type":"string","example":"Chrome"},"location":{"type":"string","example":"New York, United States"},"entityId":{"type":"number","example":1234},"entityType":{"type":"string","example":"Order"},"paymentId":{"type":"number","example":5678},"source":{"type":"string","enum":["APPLICATION","WEBSITE"],"example":"APPLICATION"},"metadata":{"type":"object","example":{"browser":"Chrome","browserVersion":"120.0","os":"Windows","osVersion":"10/11","deviceType":"Desktop","language":"en-US"}},"createdAt":{"format":"date-time","type":"string","example":"2024-01-15T10:30:00.000Z"},"errorMessage":{"type":"string"}},"required":["id","title","action","module","createdAt"]},"RegisterFcmTokenDto":{"type":"object","properties":{"token":{"type":"string","description":"Firebase FCM device/browser token"},"deviceInfo":{"type":"string","description":"Device info for identification (e.g. \"Chrome on Windows\")"}},"required":["token"]},"RemoveFcmTokenDto":{"type":"object","properties":{"token":{"type":"string","description":"FCM token to remove"}},"required":["token"]},"UpdatePushPreferenceDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable/disable push notifications"}},"required":["enabled"]},"CreateUpdateTaskStatusDto":{"type":"object","properties":{"status":{"type":"string","description":"Task status name","example":"To Do","maxLength":255},"backgroundColor":{"type":"string","description":"Background color for the status (hex color code)","example":"#FF5733","maxLength":50},"textColor":{"type":"string","description":"Text color for the status (hex color code)","example":"#FFFFFF","maxLength":50},"borderColor":{"type":"string","description":"Border color for the status (hex color code)","example":"#000000","maxLength":50}},"required":["status"]},"TaskStatusResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Task status ID","example":1},"status":{"type":"string","description":"Task status name","example":"To Do"},"backgroundColor":{"type":"string","description":"Background color for the status","example":"#6B7280"},"textColor":{"type":"string","description":"Text color for the status","example":"#FFFFFF"},"borderColor":{"type":"string","description":"Border color for the status","example":"#4B5563"},"isSystemDefined":{"type":"boolean","description":"Whether this status is system defined","example":true},"createdByName":{"type":"string","description":"Created by user name","example":"John Doe"}},"required":["id","status","isSystemDefined"]},"TaskStatusListResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items","example":4},"items":{"description":"List of task statuses","type":"array","items":{"$ref":"#/components/schemas/TaskStatusResponseDto"}},"page":{"type":"number","description":"Current page number","example":0},"size":{"type":"number","description":"Number of items per page","example":10}},"required":["totalItems","items","page","size"]},"TransferTasksDto":{"type":"object","properties":{"fromStatusId":{"type":"number","description":"Source task status ID (tasks with this status will be transferred)","example":1},"toStatusId":{"type":"number","description":"Target task status ID (tasks will be transferred to this status)","example":2}},"required":["fromStatusId","toStatusId"]},"TaskStatusInfoDto":{"type":"object","properties":{"id":{"type":"number","example":1},"status":{"type":"string","example":"To Do"},"backgroundColor":{"type":"string","example":"#6B7280"},"textColor":{"type":"string","example":"#FFFFFF"},"borderColor":{"type":"string","example":"#4B5563"}},"required":["id","status"]},"UserSummaryDto":{"type":"object","properties":{"id":{"type":"number","example":5},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","example":"john@example.com"}},"required":["id","firstName","lastName","email"]},"TaskMediaDto":{"type":"object","properties":{"id":{"type":"number","example":1},"filename":{"type":"string","example":"document.pdf"},"url":{"type":"string","example":"https://s3.amazonaws.com/bucket/uploads/tasks/uuid.pdf"},"contentType":{"type":"string","example":"application/pdf"},"size":{"type":"number","example":1024},"createdAt":{"format":"date-time","type":"string"}},"required":["id","filename","url","createdAt"]},"TaskResponseDto":{"type":"object","properties":{"id":{"type":"number","example":1},"orderId":{"type":"number","example":1001},"title":{"type":"string","example":"Follow up with customer"},"description":{"type":"string","example":"Call customer about documents"},"status":{"$ref":"#/components/schemas/TaskStatusInfoDto"},"priority":{"type":"string","example":"medium"},"dueDate":{"format":"date-time","type":"string"},"isOverdue":{"type":"boolean","example":false},"completedAt":{"format":"date-time","type":"string"},"assignedToUser":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserSummaryDto"}]},"createdByUser":{"$ref":"#/components/schemas/UserSummaryDto"},"media":{"type":"array","items":{"$ref":"#/components/schemas/TaskMediaDto"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","orderId","title","status","priority","isOverdue","createdByUser","media","createdAt","updatedAt"]},"TaskListResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","example":25},"items":{"type":"array","items":{"$ref":"#/components/schemas/TaskResponseDto"}},"page":{"type":"number","example":0},"size":{"type":"number","example":10}},"required":["totalItems","items","page","size"]},"TaskAssigneeOptionDto":{"type":"object","properties":{"id":{"type":"number","example":5},"name":{"type":"string","example":"John Doe"},"email":{"type":"string","example":"john@example.com"}},"required":["id","name","email"]},"CheckEmailDto":{"type":"object","properties":{"customerEmail":{"type":"string","description":"Email address to check","example":"customer@example.com"}},"required":["customerEmail"]},"CheckEmailResponseDto":{"type":"object","properties":{"exists":{"type":"boolean","description":"Whether the email exists","example":true},"customerEmail":{"type":"string","description":"Email address that was checked","example":"customer@example.com"}},"required":["exists","customerEmail"]},"CreateCustomerDto":{"type":"object","properties":{"customerEmail":{"type":"string","description":"Customer email address","example":"customer@example.com"}},"required":["customerEmail"]},"CustomerResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Customer ID","example":1},"customerEmail":{"type":"string","description":"Customer email address","example":"customer@example.com"},"emailValid":{"type":"boolean","description":"Whether the email is valid","example":false},"emailValidationStatus":{"type":"string","description":"Email validation status (UNKNOWN, VALID, INVALID)","example":"UNKNOWN"}},"required":["id","customerEmail","emailValid","emailValidationStatus"]},"UpdateCustomerDto":{"type":"object","properties":{"customerEmail":{"type":"string","description":"Customer email address","example":"customer@example.com"},"emailValid":{"type":"boolean","description":"Whether the email is valid","example":true}},"required":["customerEmail"]},"VerifyEmailDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com","description":"The email address to verify"},"timeout":{"type":"number","example":15,"description":"Timeout in seconds","default":15}},"required":["email"]},"VerifyEmailResponseDto":{"type":"object","properties":{"status":{"type":"string","example":"ok","description":"Status returned from the email verification API"},"isValid":{"type":"boolean","example":true,"description":"Whether the email is considered valid"}},"required":["status","isValid"]},"ProcessingSummaryResponseDto":{"type":"object","properties":{"totalAbandonedOrders":{"type":"number","example":10},"emailsSent":{"type":"number","example":5},"emailsFailed":{"type":"number","example":0},"stage1Sent":{"type":"number","example":2},"stage2Sent":{"type":"number","example":2},"stage3Sent":{"type":"number","description":"Number of stage 3 emails sent"},"stage4Sent":{"type":"number","description":"Number of stage 4 emails sent"},"stage5Sent":{"type":"number","description":"Number of stage 5 emails sent"},"stage6Sent":{"type":"number","description":"Number of stage 6 emails sent"},"stage7Sent":{"type":"number","description":"Number of stage 7 emails sent"},"stage8Sent":{"type":"number","description":"Number of stage 8 emails sent"}},"required":["totalAbandonedOrders","emailsSent","emailsFailed","stage1Sent","stage2Sent","stage3Sent","stage4Sent","stage5Sent","stage6Sent","stage7Sent","stage8Sent"]},"OrderStageInfoResponseDto":{"type":"object","properties":{"orderId":{"type":"number","example":12345},"currentStage":{"type":"number","example":1},"nextStage":{"type":"number","example":2,"nullable":true},"lastEmailSentAt":{"format":"date-time","type":"string","example":"2024-01-01T12:00:00Z","nullable":true},"nextStageEligibleAt":{"format":"date-time","type":"string","example":"2024-01-02T12:00:00Z","nullable":true},"isEligibleForNextStage":{"type":"boolean","example":true}},"required":["orderId","currentStage","nextStage","lastEmailSentAt","nextStageEligibleAt","isEligibleForNextStage"]},"ManualProcessingResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Processed successfully"},"stageInfo":{"$ref":"#/components/schemas/OrderStageInfoResponseDto"}},"required":["success","message"]},"StageConfigResponseDto":{"type":"object","properties":{"stage":{"type":"number","example":1},"delayHours":{"type":"number","example":24},"templateType":{"type":"object","example":"cart-abandonment-stage-1"},"subject":{"type":"string","example":"Complete Your Order"}},"required":["stage","delayHours","templateType","subject"]},"CreateEmailTemplateDto":{"type":"object","properties":{"templateName":{"type":"string","description":"Template name","example":"Upsell - Title Plan"},"subject":{"type":"string","description":"Email subject","example":"Complete your order with Title Plan!"},"body":{"type":"string","description":"Email body (HTML)","example":"<h1>Hi {{customerName}}</h1><p>Add Title Plan for just £10!</p>"},"upsellProducts":{"description":"Array of product IDs for upsell (null or empty for normal emails)","example":[2,3],"nullable":true,"type":"array","items":{"type":"number"}},"sortOrder":{"type":"number","description":"Sort order for display","example":1}},"required":["templateName","subject","body"]},"EmailTemplateResponseDto":{"type":"object","properties":{"id":{"type":"number"},"templateName":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"upsellProducts":{"nullable":true,"type":"array","items":{"type":"number"}},"sortOrder":{"type":"number"},"isActive":{"type":"boolean"},"createdBy":{"type":"number"},"updatedBy":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","templateName","subject","body","upsellProducts","sortOrder","isActive","createdBy","updatedBy","createdAt","updatedAt"]},"UpdateEmailTemplateDto":{"type":"object","properties":{"templateName":{"type":"string","description":"Template name","example":"Upsell - Title Plan"},"subject":{"type":"string","description":"Email subject","example":"Complete your order with Title Plan!"},"body":{"type":"string","description":"Email body (HTML)","example":"<h1>Hi {{customerName}}</h1><p>Add Title Plan for just £10!</p>"},"upsellProducts":{"description":"Array of product IDs for upsell (null or empty for normal emails)","example":[2,3],"nullable":true,"type":"array","items":{"type":"number"}},"sortOrder":{"type":"number","description":"Sort order for display","example":1}}},"CreateEmployeeDto":{"type":"object","properties":{"email":{"type":"string","example":"john.doe@example.com","description":"Employee email address"},"firstName":{"type":"string","example":"John","description":"First name"},"lastName":{"type":"string","example":"Doe","description":"Last name"},"password":{"type":"string","example":"password123","description":"Password (min 6 chars)"},"role":{"type":"string","example":"employee","description":"User role (employee or admin)","enum":["employee","admin"]},"zendeskAgentEmail":{"type":"string","example":"john.doe@company.zendesk.com","description":"Zendesk agent email used to assign tickets (optional)","nullable":true}},"required":["email","firstName","lastName","password","role"]},"ToggleStatusEmployeeDto":{"type":"object","properties":{"isActive":{"type":"boolean","description":"Active status of the employee","example":true}},"required":["isActive"]},"UpdateEmployeeDto":{"type":"object","properties":{"email":{"type":"string","example":"john.doe@example.com","description":"Employee email address"},"firstName":{"type":"string","example":"John","description":"First name"},"lastName":{"type":"string","example":"Doe","description":"Last name"},"password":{"type":"string","example":"password123","description":"Password (min 6 chars)"},"role":{"type":"string","example":"employee","description":"User role (employee or admin)","enum":["employee","admin"]},"zendeskAgentEmail":{"type":"string","example":"john.doe@company.zendesk.com","description":"Zendesk agent email used to assign tickets (optional)","nullable":true},"isActive":{"type":"boolean","example":true,"description":"Is employee active"}}},"DashboardStatsResponseDto":{"type":"object","properties":{}},"StatisticCardDto":{"type":"object","properties":{"value":{"type":"object","description":"The statistic value","example":1247},"percentageChange":{"type":"number","description":"Percentage change from previous period (2 decimal places)","example":12.5}},"required":["value","percentageChange"]},"OrderStatisticsResponseDto":{"type":"object","properties":{"totalOrders":{"description":"Total orders count statistics","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"revenue":{"description":"Revenue statistics in GBP","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"avgOrderValue":{"description":"Average order value statistics in GBP","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"pending":{"description":"Pending orders count statistics","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"multiDocumentSales":{"description":"Multi-document sales count statistics","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"multiDocumentRatio":{"description":"Multi-document sales ratio statistics","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"abandonmentRecoveredOrders":{"description":"Orders successfully paid after an abandonment email was sent","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]},"abandonmentRecoveredRevenue":{"description":"Revenue from orders successfully paid after an abandonment email was sent in GBP","allOf":[{"$ref":"#/components/schemas/StatisticCardDto"}]}},"required":["totalOrders","revenue","avgOrderValue","pending","multiDocumentSales","multiDocumentRatio","abandonmentRecoveredOrders","abandonmentRecoveredRevenue"]},"CountryFastTrackDto":{"type":"object","properties":{"countryId":{"type":"number","description":"Country ID","example":1},"countryName":{"type":"string","description":"Country name","example":"United Kingdom"},"orderCount":{"type":"number","description":"Count of express delivery orders","example":25},"ratio":{"type":"number","description":"Ratio of express delivery orders to total orders (%)","example":33.33}},"required":["countryId","countryName","orderCount","ratio"]},"FastTrackResponseDto":{"type":"object","properties":{"fastTrackByCountry":{"description":"Express delivery orders grouped by country","type":"array","items":{"$ref":"#/components/schemas/CountryFastTrackDto"}}},"required":["fastTrackByCountry"]},"HourlySlotDataDto":{"type":"object","properties":{"slotStart":{"type":"string","description":"Start time of the slot","example":"2026-01-13 07:00:00"},"slotEnd":{"type":"string","description":"End time of the slot","example":"2026-01-13 14:00:00"},"totalOrders":{"type":"number","description":"Total orders in this slot","example":150},"fastTrackOrders":{"type":"number","description":"Fast track orders in this slot","example":35},"fastTrackPercentage":{"type":"number","description":"Fast track percentage for this slot","example":23.33}},"required":["slotStart","slotEnd","totalOrders","fastTrackOrders","fastTrackPercentage"]},"FastTrackRatioHourlyResponseDto":{"type":"object","properties":{"hourlyData":{"description":"Array of hourly slot data","type":"array","items":{"$ref":"#/components/schemas/HourlySlotDataDto"}}},"required":["hourlyData"]},"KeywordReportItemDto":{"type":"object","properties":{"keyword":{"type":"string"},"salesCount":{"type":"number"},"totalRevenue":{"type":"number"},"avgOrderValue":{"type":"number"},"currency":{"type":"string","default":"GBP"},"productsSold":{"type":"string"},"totalItemsSold":{"type":"number"},"multiDocumentSales":{"type":"number","default":0},"multiDocumentRatio":{"type":"number","default":0}},"required":["keyword","salesCount","totalRevenue","avgOrderValue","currency","productsSold","totalItemsSold","multiDocumentSales","multiDocumentRatio"]},"KeywordReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KeywordReportItemDto"}}},"required":["data"]},"UtmSourceByCountryRowDto":{"type":"object","properties":{"countryId":{"type":"number"},"countryName":{"type":"string"},"utmSource":{"type":"string","description":"Normalized UTM source label"},"orderCount":{"type":"number"}},"required":["countryId","countryName","utmSource","orderCount"]},"UtmSourceRatioItemDto":{"type":"object","properties":{"utmSource":{"type":"string"},"orderCount":{"type":"number"},"ratio":{"type":"number","description":"Share of all valid orders in the range (percent, 2 decimals)"}},"required":["utmSource","orderCount","ratio"]},"UtmSourceRatioDto":{"type":"object","properties":{"totalOrders":{"type":"number","description":"Total valid orders in range (denominator for ratio). One row per distinct utmSource, sorted by order count descending."},"data":{"type":"array","items":{"$ref":"#/components/schemas/UtmSourceRatioItemDto"}}},"required":["totalOrders","data"]},"UtmSourceBySourceItemDto":{"type":"object","properties":{"utmSource":{"type":"string"},"salesCount":{"type":"number"},"totalRevenueGBP":{"type":"number"},"avgOrderValue":{"type":"number"},"multiDocumentSales":{"type":"number"},"multiDocumentRatio":{"type":"number"}},"required":["utmSource","salesCount","totalRevenueGBP","avgOrderValue","multiDocumentSales","multiDocumentRatio"]},"UtmSourceBySourceDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UtmSourceBySourceItemDto"}}},"required":["data"]},"UtmSourceStatisticsResponseDto":{"type":"object","properties":{"utmSourceByCountry":{"type":"array","items":{"$ref":"#/components/schemas/UtmSourceByCountryRowDto"}},"utmSourceRatio":{"$ref":"#/components/schemas/UtmSourceRatioDto"},"utmSourceBySource":{"$ref":"#/components/schemas/UtmSourceBySourceDto"}},"required":["utmSourceByCountry","utmSourceRatio","utmSourceBySource"]},"AbandonmentRecoverySummaryDto":{"type":"object","properties":{"totalOrders":{"type":"number"},"recoveredOrders":{"type":"number"},"recoveredRevenueGBP":{"type":"number","description":"Net recovered revenue in GBP after refunds"},"avgRecoveredOrderValue":{"type":"number"},"recoveryRate":{"type":"number","description":"Recovered orders as a percentage of valid paid orders"}},"required":["totalOrders","recoveredOrders","recoveredRevenueGBP","avgRecoveredOrderValue","recoveryRate"]},"AbandonmentRecoveryRatioItemDto":{"type":"object","properties":{"status":{"type":"string","enum":["Abandonment Recovered","Other Paid Orders"]},"orderCount":{"type":"number"},"revenueGBP":{"type":"number","description":"Net revenue in GBP after refunds"},"ratio":{"type":"number","description":"Share of valid paid orders in the range"}},"required":["status","orderCount","revenueGBP","ratio"]},"AbandonmentRecoveryRatioDto":{"type":"object","properties":{"totalOrders":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AbandonmentRecoveryRatioItemDto"}}},"required":["totalOrders","data"]},"AbandonmentRecoveryByCountryRowDto":{"type":"object","properties":{"countryId":{"type":"number"},"countryName":{"type":"string"},"totalOrders":{"type":"number"},"recoveredOrders":{"type":"number"},"recoveredRevenueGBP":{"type":"number","description":"Net recovered revenue in GBP after refunds"},"recoveredRevenueLocal":{"type":"number","description":"Net recovered revenue in country checkout currency after refunds"},"currency":{"type":"string","description":"Country ISO currency code"},"currencySymbol":{"type":"string","description":"Currency symbol for the country"},"recoveryRate":{"type":"number"}},"required":["countryId","countryName","totalOrders","recoveredOrders","recoveredRevenueGBP","recoveredRevenueLocal","currency","currencySymbol","recoveryRate"]},"AbandonmentRecoveryStatisticsResponseDto":{"type":"object","properties":{"summary":{"$ref":"#/components/schemas/AbandonmentRecoverySummaryDto"},"recoveryRatio":{"$ref":"#/components/schemas/AbandonmentRecoveryRatioDto"},"recoveryByCountry":{"type":"array","items":{"$ref":"#/components/schemas/AbandonmentRecoveryByCountryRowDto"}}},"required":["summary","recoveryRatio","recoveryByCountry"]},"MetricValueDto":{"type":"object","properties":{"value":{"type":"object","description":"Value of the metric"},"unit":{"type":"string","description":"Unit of the metric (e.g., %, GBP)"}},"required":["value","unit"]},"OrderMetricsResponseDto":{"type":"object","properties":{"averageOrderValue":{"description":"Average order value in GBP","allOf":[{"$ref":"#/components/schemas/MetricValueDto"}]},"multipleDocumentRatio":{"description":"Multiple document ratio percentage","allOf":[{"$ref":"#/components/schemas/MetricValueDto"}]},"fastTrackRatio":{"description":"Fast track ratio percentage","allOf":[{"$ref":"#/components/schemas/MetricValueDto"}]},"paperCopyRatio":{"description":"Paper copy ratio percentage","allOf":[{"$ref":"#/components/schemas/MetricValueDto"}]},"totalOrders":{"type":"number","description":"Total orders in the date range"},"byOS":{"type":"object","description":"Order counts grouped by Operating System"}},"required":["averageOrderValue","multipleDocumentRatio","fastTrackRatio","paperCopyRatio","totalOrders","byOS"]},"RevenueByCurrencyItemDto":{"type":"object","properties":{"currency":{"type":"string"},"currencySymbol":{"type":"string"},"grossRevenue":{"type":"number"},"refundedAmount":{"type":"number"},"netRevenue":{"type":"number"},"grossRevenueGBP":{"type":"number"},"refundedAmountGBP":{"type":"number"},"netRevenueGBP":{"type":"number"}},"required":["currency","currencySymbol","grossRevenue","refundedAmount","netRevenue","grossRevenueGBP","refundedAmountGBP","netRevenueGBP"]},"PurchaseAnalyticsResponseDto":{"type":"object","properties":{"byCurrency":{"type":"object","description":"Purchase value grouped by currency"},"byPaymentMethod":{"type":"object","description":"Purchase value grouped by payment method (in GBP)"},"byOS":{"type":"object","description":"Purchase count grouped by Operating System"},"revenueByCurrency":{"description":"Revenue grouped by currency with gross, refunded and net values","type":"array","items":{"$ref":"#/components/schemas/RevenueByCurrencyItemDto"}}},"required":["byCurrency","byPaymentMethod","byOS","revenueByCurrency"]},"FastTrackOSDataDto":{"type":"object","properties":{"os":{"type":"string","description":"Operating System name"},"count":{"type":"number","description":"Number of fast track orders"}},"required":["os","count"]},"FastTrackCountByOSResponseDto":{"type":"object","properties":{"totalCount":{"type":"number","description":"Total fast track orders"},"data":{"description":"Fast track counts grouped by Operating System","type":"array","items":{"$ref":"#/components/schemas/FastTrackOSDataDto"}}},"required":["totalCount","data"]},"PaperCopyOSDataDto":{"type":"object","properties":{"os":{"type":"string","description":"Operating System name"},"count":{"type":"number","description":"Number of paper copy orders"}},"required":["os","count"]},"PaperCopyCountByOSResponseDto":{"type":"object","properties":{"totalCount":{"type":"number","description":"Total paper copy orders"},"data":{"description":"Paper copy counts grouped by Operating System","type":"array","items":{"$ref":"#/components/schemas/PaperCopyOSDataDto"}}},"required":["totalCount","data"]},"EmployeeCompletedOrdersDataDto":{"type":"object","properties":{"employeeId":{"type":"number","description":"Employee user ID"},"employeeName":{"type":"string","description":"Employee full name"},"count":{"type":"number","description":"Number of orders completed by the employee"}},"required":["employeeId","employeeName","count"]},"EmployeeCompletedOrdersResponseDto":{"type":"object","properties":{"totalCount":{"type":"number","description":"Total completed orders across all employees"},"data":{"description":"Completed order counts grouped by employee","type":"array","items":{"$ref":"#/components/schemas/EmployeeCompletedOrdersDataDto"}}},"required":["totalCount","data"]},"EmployeePrintedOrdersDataDto":{"type":"object","properties":{"employeeId":{"type":"number","description":"Employee user ID"},"employeeName":{"type":"string","description":"Employee full name"},"count":{"type":"number","description":"Number of orders marked Printed by the employee"}},"required":["employeeId","employeeName","count"]},"EmployeePrintedOrdersResponseDto":{"type":"object","properties":{"totalCount":{"type":"number","description":"Total Printed orders across all employees"},"data":{"description":"Printed order counts grouped by employee","type":"array","items":{"$ref":"#/components/schemas/EmployeePrintedOrdersDataDto"}}},"required":["totalCount","data"]},"HourlyTrendItemDto":{"type":"object","properties":{"slotStart":{"type":"string","description":"Start time of the hour slot","example":"2026-01-13T00:00:00.000Z"},"avgOrderValue":{"type":"number","description":"Average order value in GBP","example":45.5},"fastTrackCount":{"type":"number","description":"Number of fast track orders","example":12}},"required":["slotStart","avgOrderValue","fastTrackCount"]},"HourlyTrendsResponseDto":{"type":"object","properties":{"data":{"description":"Array of hourly trend data","type":"array","items":{"$ref":"#/components/schemas/HourlyTrendItemDto"}}},"required":["data"]},"ProductSalesDto":{"type":"object","properties":{}},"ProductWiseSalesResponseDto":{"type":"object","properties":{"totalSales":{"type":"number","description":"Total sales across all products"},"data":{"description":"Product-wise sales data","type":"array","items":{"$ref":"#/components/schemas/ProductSalesDto"}}},"required":["totalSales","data"]},"RevenueByCurrencyResponseDto":{"type":"object","properties":{"totalGrossRevenueGBP":{"type":"number"},"totalRefundedAmountGBP":{"type":"number"},"totalNetRevenueGBP":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/RevenueByCurrencyItemDto"}}},"required":["totalGrossRevenueGBP","totalRefundedAmountGBP","totalNetRevenueGBP","data"]},"KeywordRatioResponseDto":{"type":"object","properties":{"keyword":{"type":"string","example":"google","description":"The keyword looked up (matched against utmTerm)"},"ratio":{"type":"number","example":40,"description":"Fast-track ratio in percentage: (express delivery orders for this keyword / total orders for this keyword) * 100"},"eligibleForFastTrack":{"type":"boolean","example":true,"description":"True when ratio is within [minRatio, maxRatio] (both inclusive)"},"minRatio":{"type":"number","example":0,"description":"Configured minimum ratio (env: FAST_TRACK_MIN_RATIO)"},"maxRatio":{"type":"number","example":30,"description":"Configured maximum ratio (env: FAST_TRACK_MAX_RATIO)"},"window":{"type":"string","example":"1d","description":"Lookback window used for the query (env: FAST_TRACK_RATIO_WINDOW)"}},"required":["keyword","ratio","eligibleForFastTrack","minRatio","maxRatio","window"]},"UpsellRuleProductDto":{"type":"object","properties":{"id":{"type":"number"},"productName":{"type":"string"}},"required":["id","productName"]},"UpsellRecommendationResponseDto":{"type":"object","properties":{"upsellProducts":{"type":"array","items":{"$ref":"#/components/schemas/UpsellRuleProductDto"}}},"required":["upsellProducts"]},"CreateUpsellRuleDto":{"type":"object","properties":{"sourceProductIds":{"description":"Array of source product IDs that trigger this upsell rule","example":[2,3],"type":"array","items":{"type":"number"}},"upsellProductIds":{"description":"Array of product IDs to recommend as upsell","example":[1],"type":"array","items":{"type":"number"}},"countryId":{"type":"number","description":"Country ID for country-specific rule","example":5},"isActive":{"type":"boolean","description":"Whether the rule is active","example":true,"default":true}},"required":["sourceProductIds","upsellProductIds","countryId"]},"UpsellRuleCountryDto":{"type":"object","properties":{"id":{"type":"number"},"countryName":{"type":"string"}},"required":["id","countryName"]},"UpsellRuleResponseDto":{"type":"object","properties":{"id":{"type":"number"},"sourceProducts":{"type":"array","items":{"$ref":"#/components/schemas/UpsellRuleProductDto"}},"upsellProducts":{"type":"array","items":{"$ref":"#/components/schemas/UpsellRuleProductDto"}},"country":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UpsellRuleCountryDto"}]},"isActive":{"type":"boolean"},"createdBy":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceProducts","upsellProducts","isActive","createdBy","createdAt","updatedAt"]},"UpsellRuleListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/UpsellRuleResponseDto"}},"totalItems":{"type":"number"},"page":{"type":"number"},"size":{"type":"number"}},"required":["items","totalItems","page","size"]},"UpdateUpsellRuleDto":{"type":"object","properties":{"sourceProductIds":{"description":"Array of source product IDs that trigger this upsell rule","example":[2,3],"type":"array","items":{"type":"number"}},"upsellProductIds":{"description":"Array of product IDs to recommend as upsell","example":[1],"type":"array","items":{"type":"number"}},"countryId":{"type":"number","description":"Country ID for country-specific rule","example":5},"isActive":{"type":"boolean","description":"Whether the rule is active","example":true}}},"CreateTicketDto":{"type":"object","properties":{"orderId":{"type":"number","description":"Internal order id; requester = order customerEmail; From/recipient = countries.supportMail for order country (Zendesk support address, auto-created in Zendesk if missing)","example":4521},"subject":{"type":"string","description":"Ticket subject line","example":"Payment issue — order #4521"},"body":{"type":"string","description":"The content of the initial message as HTML code","example":"<p>Customer reports duplicate charge on card ending 4242.</p>"},"isPublic":{"type":"boolean","description":"If true, the initial comment is public; if false, internal note only","default":true,"example":true},"assigneeId":{"type":"string","description":"Zendesk agent user id to assign immediately (from GET /zendesk/agents)","example":"123456789"},"groupId":{"type":"string","description":"Zendesk group id (often used with assignee)","example":"123456789"},"tags":{"description":"Ticket tags","example":["land-registry","payment"],"type":"array","items":{"type":"string"}},"priority":{"type":"string","description":"Zendesk ticket priority","enum":["low","normal","high","urgent"],"example":"normal"},"customStatusId":{"type":"string","description":"The numeric ID of the custom ticket status from GET /zendesk/tickets/statuses","example":"32664110523537"}},"required":["orderId","subject","body"]},"ReplyToTicketDto":{"type":"object","properties":{"body":{"type":"string","description":"The content of the reply as HTML code","example":"<p>Thank you for your message. We are looking into it.</p>"},"isPublic":{"type":"boolean","description":"Whether the comment is public or internal","default":true,"example":true},"customStatusId":{"type":"string","description":"The numeric ID of the custom ticket status from the statuses API","example":"32664110523537"}},"required":["body"]},"UpdateTicketStatusDto":{"type":"object","properties":{"customStatusId":{"type":"string","description":"The numeric ID of the custom ticket status from the statuses API","example":"32664110523537"}},"required":["customStatusId"]},"AssignAgentDto":{"type":"object","properties":{"assigneeId":{"type":"string","description":"The numeric ID of the agent to assign the ticket to","example":"123456789"},"groupId":{"type":"string","description":"The numeric ID of the group to assign the ticket to","example":"123456789"}},"required":["assigneeId"]},"InternalDocumentUploaderDto":{"type":"object","properties":{"id":{"type":"number","example":8},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","example":"john@example.com"}},"required":["id","firstName","lastName","email"]},"OrderInternalDocumentDto":{"type":"object","properties":{"id":{"type":"number","example":1},"orderId":{"type":"number","example":1302},"fileName":{"type":"string","example":"ef9b2a52-06cb-44ac-87ec-a619d10f24a1.pdf"},"originalFileName":{"type":"string","example":"search-result.pdf"},"filePath":{"type":"string","example":"https://s3.eu-west-1.amazonaws.com/example-bucket/uploads/internal-documents/ef9b2a52-06cb-44ac-87ec-a619d10f24a1.pdf"},"mimeType":{"type":"string","example":"application/pdf"},"fileSize":{"type":"number","example":125845},"uploadedBy":{"type":"number","example":8},"uploadedByUser":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/InternalDocumentUploaderDto"}]},"title":{"type":"string","example":"Registry extract"},"notes":{"type":"string","example":"Re-check signatures before sharing with ops."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","orderId","fileName","originalFileName","filePath","uploadedBy","createdAt","updatedAt"]},"OrderInternalDocumentListResponseDto":{"type":"object","properties":{"totalItems":{"type":"number","example":25},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderInternalDocumentDto"}},"page":{"type":"number","example":0},"size":{"type":"number","example":10}},"required":["totalItems","items","page","size"]}}}}