{"data":{"openapi":"3.0.0","info":{"title":"Salonify Public API","description":"The Salonify public developer API. Authenticate every request with an API key in the `X-API-Key` header (format `sk_live_...`). API keys are created in the dashboard and require the PRO plan or higher. Each key holds a subset of the scopes listed in the `ApiKey` security scheme. Available scopes: bookings:read, bookings:write, services:read, services:write, staff:read, staff:write, customers:read, customers:write, reviews:read, reviews:write, schedule:read, schedule:write, business:read, products:read, products:write, gift-cards:read, gift-cards:write, loyalty:read, loyalty:write, availability:read, analytics:read, payments:read, invoices:read, locations:read, locations:write. Rate limit: 1000 requests / 60s per key (see X-RateLimit-* headers).","version":"1.0"},"servers":[{"url":"/api/v1"}],"tags":[{"name":"cross-salon-reports"},{"name":"Public API"},{"name":"Bookings"},{"name":"Payments"},{"name":"Loyalty"},{"name":"Gift Cards"},{"name":"Customers"},{"name":"Reviews"},{"name":"Invoices"},{"name":"Products"}],"paths":{"/api/v1/businesses/cross-salon/overview":{"get":{"operationId":"CrossSalonReportsController_overview","summary":"Aggregated bookings + revenue across owned salons","parameters":[{"name":"from","required":true,"in":"query","schema":{"type":"string"}},{"name":"to","required":true,"in":"query","schema":{"type":"string"}},{"name":"businessIds","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Overview totals + per-business breakdown + daily series"}},"tags":["cross-salon-reports","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/cross-salon/staff-performance":{"get":{"operationId":"CrossSalonReportsController_staffPerformance","summary":"Per-staff bookings + revenue across owned salons","parameters":[{"name":"from","required":true,"in":"query","schema":{"type":"string"}},{"name":"to","required":true,"in":"query","schema":{"type":"string"}},{"name":"businessIds","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["cross-salon-reports","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/cross-salon/invoices":{"get":{"operationId":"CrossSalonReportsController_invoices","summary":"All Salonify invoices across owned salons","parameters":[{"name":"businessIds","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["cross-salon-reports","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/bookings":{"post":{"operationId":"BookingsController_createBooking","summary":"Create a new booking","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingDto"}}}},"responses":{"201":{"description":"Booking created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingResponseDto"}}}}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"get":{"operationId":"BookingsController_getBookings","summary":"List all bookings for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["PENDING","CONFIRMED","IN_PROGRESS","COMPLETED","CANCELLED","NO_SHOW"],"type":"string"}},{"name":"paymentStatus","required":false,"in":"query","description":"Comma-separated payment statuses to filter by (e.g. PENDING,ON_SITE)","schema":{"type":"string"}},{"name":"staffId","required":false,"in":"query","schema":{"type":"string"}},{"name":"customerId","required":false,"in":"query","schema":{"type":"string"}},{"name":"startDate","required":false,"in":"query","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order for date","schema":{"enum":["asc","desc"],"type":"string"}},{"name":"search","required":false,"in":"query","description":"Search by customer name, email, phone, or booking number","schema":{"type":"string"}}],"responses":{"200":{"description":"List of bookings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedBookingsResponseDto"}}}}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/bookings/stats/revenue":{"get":{"operationId":"BookingsController_getBookingRevenueStats","summary":"Booked gross revenue + distinct customers for a period","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"startDate","required":true,"in":"query","schema":{"type":"string"}},{"name":"endDate","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/bookings/{bookingId}":{"get":{"operationId":"BookingsController_getBooking","summary":"Get a specific booking","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"bookingId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Booking details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponseDto"}}}}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/bookings/{bookingId}/cancel":{"patch":{"operationId":"BookingsController_cancelBooking","summary":"Cancel a booking","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"bookingId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingDto"}}}},"responses":{"200":{"description":"Booking cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponseDto"}}}}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/bookings/{bookingId}/reschedule":{"patch":{"operationId":"BookingsController_rescheduleBooking","summary":"Reschedule a booking","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"bookingId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleBookingDto"}}}},"responses":{"200":{"description":"Booking rescheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponseDto"}}}}},"tags":["Bookings","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments":{"get":{"operationId":"PaymentsController_list","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/refunds":{"get":{"operationId":"PaymentsController_listRefunds","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}},{"name":"status","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/refunds/pending-count":{"get":{"operationId":"PaymentsController_pendingCount","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/memberships":{"get":{"operationId":"PaymentsController_listMembershipPayments","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/bookings/{bookingId}/trace":{"get":{"operationId":"PaymentsController_trace","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}},{"name":"bookingId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/v2/all":{"get":{"operationId":"PaymentsController_listAllV2","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}},{"name":"from","required":true,"in":"query","schema":{"type":"string"}},{"name":"to","required":true,"in":"query","schema":{"type":"string"}},{"name":"source","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/v2/fees-summary":{"get":{"operationId":"PaymentsController_feesSummary","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}},{"name":"from","required":true,"in":"query","schema":{"type":"string"}},{"name":"to","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/payments/my-fees":{"get":{"operationId":"PaymentsController_myFees","parameters":[{"name":"businessId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Payments","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/programs":{"post":{"operationId":"LoyaltyController_createProgram","summary":"Create a loyalty program for a business","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLoyaltyProgramDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoyaltyProgramResponseDto"}}}}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/programs/{programId}":{"patch":{"operationId":"LoyaltyController_updateProgram","summary":"Update a loyalty program","parameters":[{"name":"programId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLoyaltyProgramDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoyaltyProgramResponseDto"}}}}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/business/{businessId}/cards":{"get":{"operationId":"LoyaltyController_getBusinessCards","summary":"Get all loyalty cards for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyCardResponseDto"}}}}}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/business/{businessId}/stats":{"get":{"operationId":"LoyaltyController_getOwnerStats","summary":"Loyalty stats for the owner Overview tab (members, wallet installs, points, stamps, campaigns, retention, 30d timeseries)","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/business/{businessId}/activity":{"get":{"operationId":"LoyaltyController_getActivityFeed","summary":"Loyalty activity feed for the owner Activity tab (newest first, cursor-paginated)","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}},{"name":"type","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/campaigns/business/{businessId}":{"get":{"operationId":"LoyaltyController_listCampaigns","summary":"List wallet push campaigns for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/campaigns":{"post":{"operationId":"LoyaltyController_createCampaign","summary":"Create a wallet push campaign (DRAFT, or SCHEDULED if scheduledAt given)","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWalletCampaignDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/campaigns/{id}/send":{"post":{"operationId":"LoyaltyController_sendCampaign","summary":"Send a wallet push campaign to enrolled customers now","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/campaign-templates/business/{businessId}":{"get":{"operationId":"LoyaltyController_listCampaignTemplates","summary":"List saved custom wallet campaign templates for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/campaign-templates":{"post":{"operationId":"LoyaltyController_createCampaignTemplate","summary":"Save a custom wallet campaign template","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWalletCampaignTemplateDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/stamps":{"post":{"operationId":"LoyaltyController_addStamp","summary":"Add stamp(s) to a loyalty card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddStampDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/stamps/remove":{"post":{"operationId":"LoyaltyController_removeStamp","summary":"Remove stamp(s) from a loyalty card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveStampDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/points/adjust":{"post":{"operationId":"LoyaltyController_adjustPoints","summary":"Manually award (positive) or deduct (negative) points on a loyalty card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustPointsDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/loyalty/redeem":{"post":{"operationId":"LoyaltyController_redeemReward","summary":"Redeem a reward from a loyalty card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemRewardDto"}}}},"responses":{"201":{"description":""}},"tags":["Loyalty","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/gift-cards/settings/{businessId}":{"patch":{"operationId":"GiftCardsController_updateSettings","summary":"Update gift card settings","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGiftCardSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftCardSettingsResponseDto"}}}}},"tags":["Gift Cards","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"get":{"operationId":"GiftCardsController_getSettings","summary":"Get gift card settings for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftCardSettingsResponseDto"}}}}},"tags":["Gift Cards","Public API"],"security":[{"ApiKey":[]}]}},"/api/v1/gift-cards/purchase":{"post":{"operationId":"GiftCardsController_purchaseGiftCard","summary":"Purchase a gift card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseGiftCardDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftCardResponseDto"}}}}},"tags":["Gift Cards","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/gift-cards/redeem":{"post":{"operationId":"GiftCardsController_redeemGiftCard","summary":"Redeem amount from a gift card","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemGiftCardDto"}}}},"responses":{"201":{"description":""}},"tags":["Gift Cards","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/gift-cards/business/{businessId}":{"get":{"operationId":"GiftCardsController_getBusinessGiftCards","summary":"Get all gift cards for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GiftCardResponseDto"}}}}}},"tags":["Gift Cards","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/customers":{"get":{"operationId":"CustomersController_getCustomers","summary":"List customers for a business","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Search across name, email, phone","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","schema":{"default":"all","enum":["all","walk-in","online"],"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"Paginated list of customers"}},"tags":["Customers","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"post":{"operationId":"CustomersController_createWalkInCustomer","summary":"Create a walk-in customer","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWalkInCustomerDto"}}}},"responses":{"201":{"description":"Walk-in customer created"}},"tags":["Customers","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/customers/search":{"get":{"operationId":"CustomersController_searchCustomers","summary":"Search all customers by name, email, or phone","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"q","required":true,"in":"query","description":"Search query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Max results (default 10)","schema":{"type":"string"}}],"responses":{"200":{"description":"List of matching customers"}},"tags":["Customers","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/customers/{customerId}":{"get":{"operationId":"CustomersController_getCustomerDetails","summary":"Get customer details with booking history","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Customer details"}},"tags":["Customers","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/customers/{customerId}/notes":{"patch":{"operationId":"CustomersController_updateCustomerNotes","summary":"Update internal notes for a customer","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"customerId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerNotesDto"}}}},"responses":{"200":{"description":"Notes updated"}},"tags":["Customers","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/reviews/all":{"get":{"operationId":"ReviewsController_getAllBusinessReviews","summary":"Get all reviews for a business (including unapproved, for business owner)","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"minRating","required":false,"in":"query","schema":{"minimum":1,"maximum":5,"type":"number"}},{"name":"maxRating","required":false,"in":"query","schema":{"minimum":1,"maximum":5,"type":"number"}},{"name":"isApproved","required":false,"in":"query","description":"Filter by approval status","schema":{"type":"boolean"}},{"name":"isReported","required":false,"in":"query","description":"Filter by reported status","schema":{"type":"boolean"}},{"name":"hasResponse","required":false,"in":"query","description":"Filter by response status","schema":{"type":"boolean"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"sortBy","required":false,"in":"query","schema":{"default":"createdAt","enum":["createdAt","rating"],"type":"string"}},{"name":"sortOrder","required":false,"in":"query","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}}],"responses":{"200":{"description":"List of reviews","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReviewsResponseDto"}}}}},"tags":["Reviews","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/reviews/{reviewId}/response":{"post":{"operationId":"ReviewsController_createReviewResponse","summary":"Create a response to a review","parameters":[{"name":"businessId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reviewId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewResponseDto"}}}},"responses":{"201":{"description":"Response created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewResponseDto"}}}}},"tags":["Reviews","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/invoices":{"get":{"operationId":"InvoicesController_getBusinessInvoices","summary":"List invoices for a business","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business ID","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"enum":["paid","open","void","uncollectible"],"type":"string"}},{"name":"dateFrom","required":false,"in":"query","description":"Start date filter (ISO string)","schema":{"type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"End date filter (ISO string)","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedInvoicesDto"}}}}},"tags":["Invoices","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/invoices/summary":{"get":{"operationId":"InvoicesController_getInvoiceSummary","summary":"Get invoice summary/stats for a business","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business ID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceSummaryDto"}}}}},"tags":["Invoices","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/invoices/{id}":{"get":{"operationId":"InvoicesController_getInvoiceById","summary":"Get a specific invoice","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business ID","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Invoice ID","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponseDto"}}}}},"tags":["Invoices","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/invoices/{id}/download":{"get":{"operationId":"InvoicesController_getDownloadUrl","summary":"Get PDF download URL for an invoice","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business ID","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","description":"Invoice ID","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Invoices","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/products":{"post":{"operationId":"ProductsController_create","summary":"Create product","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"201":{"description":"Product created"},"400":{"description":"Invalid category"},"404":{"description":"Business not found"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"get":{"operationId":"ProductsController_findAll","summary":"Get all products (paginated)","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}},{"name":"categoryId","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["ACTIVE","DRAFT","UNLISTED","ARCHIVED","INACTIVE","OUT_OF_STOCK"],"type":"string"}}],"responses":{"200":{"description":"Paginated list of products"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/products/low-stock":{"get":{"operationId":"ProductsController_getLowStockAlerts","summary":"Get products with low stock alerts","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"List of low stock products"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/products/{productId}":{"get":{"operationId":"ProductsController_findOne","summary":"Get product by ID","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","description":"Product UUID","schema":{"type":"string"}}],"responses":{"200":{"description":"Product details"},"404":{"description":"Product not found"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"patch":{"operationId":"ProductsController_update","summary":"Update product","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","description":"Product UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":"Product updated"},"404":{"description":"Product not found"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]},"delete":{"operationId":"ProductsController_remove","summary":"Delete product (soft delete)","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","description":"Product UUID","schema":{"type":"string"}}],"responses":{"204":{"description":"Product deleted"},"404":{"description":"Product not found"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}},"/api/v1/businesses/{businessId}/products/{productId}/inventory":{"post":{"operationId":"ProductsController_adjustInventory","summary":"Adjust product inventory","parameters":[{"name":"businessId","required":true,"in":"path","description":"Business UUID","schema":{"type":"string"}},{"name":"productId","required":true,"in":"path","description":"Product UUID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustInventoryDto"}}}},"responses":{"200":{"description":"Inventory adjusted"},"400":{"description":"Invalid adjustment or tracking not enabled"},"404":{"description":"Product not found"}},"tags":["Products","Public API"],"security":[{"bearer":[]},{"ApiKey":[]}]}}},"components":{"schemas":{"CreateBookingDto":{"type":"object","properties":{"date":{"type":"string","example":"2024-12-20"},"startTime":{"type":"string","example":"09:00"},"staffId":{"type":"string","description":"Staff member ID (optional, auto-assigned if not provided)"},"services":{"description":"Services to book","type":"array","items":{"$ref":"#/components/schemas/BookingServiceDto"}},"customerId":{"type":"string","description":"Customer ID (for business-initiated bookings on behalf of a customer)"},"customerName":{"type":"string","description":"Walk-in customer name (when no registered customer)"},"customerEmail":{"type":"string","description":"Walk-in customer email"},"customerPhone":{"type":"string","description":"Walk-in customer phone"},"isWalkIn":{"type":"boolean","description":"Whether this is a walk-in customer"},"customerNotes":{"type":"string","description":"Customer notes or special requests"},"addressId":{"type":"string","description":"For mobile bookings - user address ID"},"mobileAddress":{"type":"string","description":"For mobile bookings - custom address if no saved address"},"paymentMethod":{"type":"string","enum":["ON_SITE","ONLINE","WORK_CARD","WORK_BUNDLE"],"description":"Payment method - ON_SITE (default) or ONLINE","default":"ON_SITE"},"savedPaymentMethodId":{"type":"string","description":"Saved Stripe PaymentMethod id to charge (must belong to the customer)."},"saveCard":{"type":"boolean","description":"Save the card used for this booking for future off_session charges."},"tipAmount":{"type":"number","description":"Trinkgeld / tip in main currency units (e.g. EUR). 100% goes to the venue. 0..500."},"skipPaymentIntent":{"type":"boolean","description":"Internal: defer Stripe charge to caller (e.g. widget creates own Checkout Session)."},"couponCode":{"type":"string","description":"Coupon code to apply discount"},"giftCardCodes":{"description":"Gift card codes to apply","type":"array","items":{"type":"string"}},"useSalonifyBalance":{"type":"number","description":"Amount to pay from Salonify Balance"},"workCompanyId":{"type":"string","description":"Salonify Work — corporate wallet to charge (paymentMethod must be WORK_CARD)."},"forceOutsideHours":{"type":"boolean","description":"Force booking outside business hours (business owner only)"},"allowOverlap":{"type":"boolean","description":"Allow overlapping bookings on same staff (business owner only)"},"bookingSource":{"type":"string","description":"Booking source channel","enum":["WEBSITE","WIDGET","MOBILE_APP","DASHBOARD","MARKETPLACE","GOOGLE"]}},"required":["date","startTime","services"]},"CreateBookingResponseDto":{"type":"object","properties":{}},"PaginatedBookingsResponseDto":{"type":"object","properties":{}},"BookingResponseDto":{"type":"object","properties":{}},"CancelBookingDto":{"type":"object","properties":{"cancelReason":{"type":"string","description":"Reason for cancellation"},"cancelReasonKey":{"type":"string","description":"Predefined cancellation reason key","enum":["scheduleConflict","personalReasons","illness","providerUnreachable","noLongerNeeded","other"]}}},"RescheduleBookingDto":{"type":"object","properties":{"date":{"type":"string","example":"2024-12-21"},"startTime":{"type":"string","example":"10:00"},"staffId":{"type":"string"}},"required":["date","startTime"]},"CreateLoyaltyProgramDto":{"type":"object","properties":{"businessId":{"type":"string","description":"Business ID"},"name":{"type":"string","description":"Program name"},"type":{"type":"string","description":"Program mechanic: STAMPS or POINTS","enum":["STAMPS","POINTS"],"default":"POINTS"},"description":{"type":"string","description":"Program description"},"stampsRequired":{"type":"number","description":"Number of stamps required for reward (legacy stamp programs)","default":10},"rewardDescription":{"type":"string","description":"Reward description (legacy stamp programs)"},"pointsPerEuro":{"type":"number","description":"Points awarded per €1 spent","default":5},"pointsPerReview":{"type":"number","description":"Points awarded for leaving a review","default":50},"pointsPerAppointmentsMilestone":{"type":"number","description":"Points awarded when the appointments milestone is hit","default":1000},"appointmentsMilestoneSize":{"type":"number","description":"Number of completed appointments per milestone payout","default":10},"customPointsPerEuro":{"type":"number","description":"Custom redemption rate: points required to convert into €1","default":100},"rewardValue":{"type":"number","description":"Reward monetary value"},"cardDesign":{"type":"string","description":"Card design template ID"},"logoUrl":{"type":"string","description":"Logo URL"},"primaryColor":{"type":"string","description":"Primary color","default":"#7C3AED"},"secondaryColor":{"type":"string","description":"Secondary/accent color"},"backgroundColor":{"type":"string","description":"Card background/surface color (hex). null = default/white."},"coverImageUrl":{"type":"string","description":"Cover/hero image URL"},"stampIconUrl":{"type":"string","description":"Custom stamp image URL"},"stampIcon":{"type":"string","description":"Lucide icon name for stamp","default":"Star"},"cardTextColors":{"type":"object","description":"Per-text-element hex color overrides for the loyalty card. Optional keys: title, subtitle, value, label, businessName (each a hex string like \"#FFFFFF\"). Omit/null = sensible defaults.","additionalProperties":{"type":"string"}},"coverOverlayOpacity":{"type":"number","description":"Cover/header image darken-overlay opacity (0-90, percent). 0 = no overlay.","default":35},"couponEnabled":{"type":"boolean","description":"Generate coupon on card completion","default":true},"couponDiscountType":{"type":"string","description":"Coupon discount type","enum":["PERCENTAGE","FIXED_AMOUNT"]},"couponDiscountValue":{"type":"number","description":"Coupon discount value"},"couponApplicableServices":{"description":"Service IDs coupon applies to (empty = all)","type":"array","items":{"type":"string"}},"couponValidDays":{"type":"number","description":"Coupon validity in days","default":90},"rewardType":{"type":"string","description":"Reward type","enum":["FREE_SERVICE","PERCENTAGE_DISCOUNT","FIXED_DISCOUNT"],"default":"FREE_SERVICE"},"autoStampTrigger":{"type":"string","description":"Auto-stamp trigger","enum":["ON_COMPLETED","ON_CONFIRMED"],"default":"ON_COMPLETED"},"autoStampEnabled":{"type":"boolean","description":"Enable automatic stamps","default":true},"birthdayEnabled":{"type":"boolean","description":"Enable the birthday reward (daily cron awards birthdayBonus on the customer’s birthday)","default":false},"birthdayBonus":{"type":"number","description":"Birthday bonus amount — POINTS for a POINTS program, STAMPS for a STAMPS program","default":0}},"required":["businessId","name"]},"LoyaltyProgramResponseDto":{"type":"object","properties":{"id":{"type":"string"},"businessId":{"type":"string"},"type":{"type":"string","description":"Program mechanic: STAMPS or POINTS","enum":["STAMPS","POINTS"]},"name":{"type":"string"},"description":{"type":"string"},"stampsRequired":{"type":"number"},"rewardDescription":{"type":"string"},"rewardValue":{"type":"number"},"primaryColor":{"type":"string"},"secondaryColor":{"type":"string"},"backgroundColor":{"type":"string","description":"Card background/surface color (hex). null = default/white."},"coverImageUrl":{"type":"string"},"stampIconUrl":{"type":"string"},"stampIcon":{"type":"string"},"cardTextColors":{"type":"object","description":"Per-text-element hex color overrides. Keys: title, subtitle, value, label, businessName.","additionalProperties":{"type":"string"}},"coverOverlayOpacity":{"type":"number","description":"Cover/header image darken-overlay opacity (0-90).","default":35},"logoUrl":{"type":"string"},"couponEnabled":{"type":"boolean"},"couponDiscountType":{"type":"string"},"couponDiscountValue":{"type":"number"},"couponApplicableServices":{"type":"array","items":{"type":"string"}},"couponValidDays":{"type":"number"},"isActive":{"type":"boolean"}},"required":["id","businessId","type","name","stampsRequired","rewardDescription","primaryColor","coverOverlayOpacity","couponEnabled","couponValidDays","isActive"]},"UpdateLoyaltyProgramDto":{"type":"object","properties":{"name":{"type":"string","description":"Program name"},"type":{"type":"string","description":"Program mechanic: STAMPS or POINTS","enum":["STAMPS","POINTS"]},"description":{"type":"string","description":"Program description"},"stampsRequired":{"type":"number","description":"Number of stamps required for reward (legacy)"},"rewardDescription":{"type":"string","description":"Reward description (legacy)"},"rewardValue":{"type":"number","description":"Reward monetary value"},"pointsPerEuro":{"type":"number","description":"Points awarded per €1 spent"},"pointsPerReview":{"type":"number","description":"Points awarded for leaving a review"},"pointsPerAppointmentsMilestone":{"type":"number","description":"Points awarded when the appointments milestone is hit"},"appointmentsMilestoneSize":{"type":"number","description":"Number of completed appointments per milestone payout"},"customPointsPerEuro":{"type":"number","description":"Custom redemption rate: points required to convert into €1"},"cardDesign":{"type":"string","description":"Card design template ID"},"logoUrl":{"type":"string","description":"Logo URL"},"primaryColor":{"type":"string","description":"Primary color"},"secondaryColor":{"type":"string","description":"Secondary/accent color"},"backgroundColor":{"type":"string","description":"Card background/surface color (hex). null = default/white."},"coverImageUrl":{"type":"string","description":"Cover/hero image URL"},"stampIconUrl":{"type":"string","description":"Custom stamp image URL"},"stampIcon":{"type":"string","description":"Lucide icon name for stamp"},"cardTextColors":{"type":"object","description":"Per-text-element hex color overrides for the loyalty card. Optional keys: title, subtitle, value, label, businessName (each a hex string like \"#FFFFFF\"). Omit/null = sensible defaults.","additionalProperties":{"type":"string"}},"coverOverlayOpacity":{"type":"number","description":"Cover/header image darken-overlay opacity (0-90, percent). 0 = no overlay."},"couponEnabled":{"type":"boolean","description":"Generate coupon on card completion"},"couponDiscountType":{"type":"string","description":"Coupon discount type","enum":["PERCENTAGE","FIXED_AMOUNT"]},"couponDiscountValue":{"type":"number","description":"Coupon discount value"},"couponApplicableServices":{"description":"Service IDs coupon applies to (empty = all)","type":"array","items":{"type":"string"}},"couponValidDays":{"type":"number","description":"Coupon validity in days"},"rewardType":{"type":"string","description":"Reward type","enum":["FREE_SERVICE","PERCENTAGE_DISCOUNT","FIXED_DISCOUNT"],"default":"FREE_SERVICE"},"autoStampTrigger":{"type":"string","description":"Auto-stamp trigger","enum":["ON_COMPLETED","ON_CONFIRMED"],"default":"ON_COMPLETED"},"autoStampEnabled":{"type":"boolean","description":"Enable automatic stamps","default":true},"isActive":{"type":"boolean","description":"Is program active"},"birthdayEnabled":{"type":"boolean","description":"Enable the birthday reward (daily cron awards birthdayBonus on the customer’s birthday)"},"birthdayBonus":{"type":"number","description":"Birthday bonus amount — POINTS for a POINTS program, STAMPS for a STAMPS program"}}},"LoyaltyCardResponseDto":{"type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string"},"currentStamps":{"type":"number"},"totalStamps":{"type":"number"},"rewardsRedeemed":{"type":"number"},"appleWalletUrl":{"type":"string"},"googleWalletUrl":{"type":"string"},"isActive":{"type":"boolean"},"program":{"$ref":"#/components/schemas/LoyaltyProgramResponseDto"}},"required":["id","customerId","currentStamps","totalStamps","rewardsRedeemed","isActive","program"]},"CreateWalletCampaignDto":{"type":"object","properties":{"businessId":{"type":"string","description":"Business ID"},"title":{"type":"string","description":"Campaign title (shown as the wallet message header)"},"message":{"type":"string","description":"Campaign message body pushed to wallet passes"},"segment":{"type":"string","description":"Recipient segment","enum":["ALL","STAMPS_NEAR_REWARD","POINTS_MIN","INACTIVE_30D"],"default":"ALL"},"segmentValue":{"type":"number","description":"Segment threshold: STAMPS_NEAR_REWARD = stamps remaining (default 1); POINTS_MIN = minimum points balance"},"bonusPoints":{"type":"number","description":"Bonus points (POINTS mode) or stamps (STAMPS mode) granted to every recipient on send"},"emoji":{"type":"string","description":"Optional emoji/icon displayed with the campaign in the dashboard"},"audience":{"type":"string","description":"Audience contract from the dashboard (ALL, MIN_POINTS, REWARD_READY, INACTIVE_30D, BIRTHDAY_MONTH). The client also sends the legacy `segment`/`segmentValue` which drives recipient selection; this is accepted for forward-compat."},"minPoints":{"type":"number","description":"Minimum points balance when audience = MIN_POINTS (mirrors segmentValue)"},"scheduledAt":{"type":"string","description":"ISO date to schedule the send; omit to save as DRAFT"}},"required":["businessId","title","message"]},"CreateWalletCampaignTemplateDto":{"type":"object","properties":{"businessId":{"type":"string","description":"Business ID"},"name":{"type":"string","description":"Template name (shown in the saved-templates list)"},"title":{"type":"string","description":"Campaign title (wallet message header)"},"message":{"type":"string","description":"Campaign message body"},"emoji":{"type":"string","description":"Optional emoji/icon to display with the template"}},"required":["businessId","name","title","message"]},"AddStampDto":{"type":"object","properties":{"cardId":{"type":"string","description":"Loyalty card ID"},"bookingId":{"type":"string","description":"Associated booking ID"},"note":{"type":"string","description":"Note for the stamp"},"count":{"type":"number","description":"Number of stamps to add","default":1}},"required":["cardId"]},"RemoveStampDto":{"type":"object","properties":{"cardId":{"type":"string","description":"Loyalty card ID"},"count":{"type":"number","description":"Number of stamps to remove","default":1}},"required":["cardId"]},"AdjustPointsDto":{"type":"object","properties":{"cardId":{"type":"string","description":"Loyalty card ID"},"amount":{"type":"number","description":"Points to add (positive) or deduct (negative). Resulting balance is floored at 0."},"note":{"type":"string","description":"Reason / note for the manual adjustment"}},"required":["cardId","amount"]},"RedeemRewardDto":{"type":"object","properties":{"cardId":{"type":"string","description":"Loyalty card ID"},"bookingId":{"type":"string","description":"Associated booking ID"}},"required":["cardId"]},"UpdateGiftCardSettingsDto":{"type":"object","properties":{"isEnabled":{"type":"boolean","description":"Enable gift cards"},"minAmount":{"type":"number","description":"Minimum gift card amount"},"maxAmount":{"type":"number","description":"Maximum gift card amount"},"expirationMonths":{"type":"number","description":"Expiration in months"},"designs":{"description":"Available design templates","type":"array","items":{"type":"string"}}}},"GiftCardSettingsResponseDto":{"type":"object","properties":{"id":{"type":"string"},"businessId":{"type":"string"},"isEnabled":{"type":"boolean"},"minAmount":{"type":"number"},"maxAmount":{"type":"number"},"expirationMonths":{"type":"number"},"designs":{"type":"array","items":{"type":"string"}}},"required":["id","businessId","isEnabled","minAmount","maxAmount","expirationMonths"]},"PurchaseGiftCardDto":{"type":"object","properties":{"businessId":{"type":"string","description":"Business ID"},"amount":{"type":"number","description":"Gift card amount"},"recipientName":{"type":"string","description":"Recipient name"},"recipientEmail":{"type":"string","description":"Recipient email"},"personalMessage":{"type":"string","description":"Personal message"},"designId":{"type":"string","description":"Design ID"},"deliveryMethod":{"type":"string","description":"Delivery method: EMAIL or PRINT","enum":["EMAIL","PRINT"]},"scheduledDeliveryAt":{"type":"string","description":"Scheduled delivery date (ISO string)"}},"required":["businessId","amount"]},"GiftCardResponseDto":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"initialAmount":{"type":"number"},"remainingAmount":{"type":"number"},"recipientName":{"type":"string"},"recipientEmail":{"type":"string"},"personalMessage":{"type":"string"},"isRedeemed":{"type":"boolean"},"expiresAt":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"}},"required":["id","code","initialAmount","remainingAmount","isRedeemed","expiresAt","createdAt"]},"RedeemGiftCardDto":{"type":"object","properties":{"code":{"type":"string","description":"Gift card code"},"amount":{"type":"number","description":"Amount to redeem"},"bookingId":{"type":"string","description":"Booking ID to apply to"}},"required":["code","amount"]},"CreateWalkInCustomerDto":{"type":"object","properties":{"firstName":{"type":"string","example":"John","minLength":2},"lastName":{"type":"string","example":"Doe","minLength":2},"email":{"type":"string","example":"john@example.com"},"phone":{"type":"string","example":"+352621123456"}},"required":["firstName","lastName"]},"UpdateCustomerNotesDto":{"type":"object","properties":{"notes":{"type":"string","description":"Internal notes about the customer"}},"required":["notes"]},"PaginatedReviewsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewResponseDto"}},"meta":{"type":"object"}},"required":["data","meta"]},"CreateReviewResponseDto":{"type":"object","properties":{"content":{"type":"string","maxLength":1000}},"required":["content"]},"ReviewResponseDto":{"type":"object","properties":{"id":{"type":"string"},"rating":{"type":"number"},"comment":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"customer":{"type":"object"},"booking":{"type":"object"},"response":{"type":"object"}},"required":["id","rating","createdAt","updatedAt"]},"PaginatedInvoicesDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceResponseDto"}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}},"required":["data","total","page","limit","totalPages"]},"InvoiceSummaryDto":{"type":"object","properties":{"totalPaid":{"type":"number","description":"Total amount paid"},"totalOutstanding":{"type":"number","description":"Total amount outstanding (open invoices)"},"paidCount":{"type":"number","description":"Number of paid invoices"},"openCount":{"type":"number","description":"Number of open invoices"},"voidCount":{"type":"number","description":"Number of void invoices"},"uncollectibleCount":{"type":"number","description":"Number of uncollectible invoices"},"lastPaymentDate":{"format":"date-time","type":"string","description":"Last payment date"},"currency":{"type":"string","description":"Currency"}},"required":["totalPaid","totalOutstanding","paidCount","openCount","voidCount","uncollectibleCount","currency"]},"InvoiceResponseDto":{"type":"object","properties":{"id":{"type":"string"},"subscriptionId":{"type":"string"},"stripeInvoiceId":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string","enum":["paid","open","void","uncollectible"]},"periodStart":{"format":"date-time","type":"string"},"periodEnd":{"format":"date-time","type":"string"},"paidAt":{"format":"date-time","type":"string"},"invoiceUrl":{"type":"string"},"invoicePdf":{"type":"string"},"createdAt":{"format":"date-time","type":"string"}},"required":["id","subscriptionId","amount","currency","status","periodStart","periodEnd","createdAt"]},"CreateProductDto":{"type":"object","properties":{"name":{"type":"string","example":"Hair Wax Matte Finish"},"description":{"type":"string","example":"Professional hair wax with matte finish, 100ml"},"sku":{"type":"string","example":"HW-MATTE-100"},"ean":{"type":"string","example":"5901234123457"},"purchasePrice":{"type":"number","example":8.5},"sellingPrice":{"type":"number","example":18.99},"vatRate":{"type":"string","enum":["STANDARD","REDUCED","SUPER_REDUCED","ZERO","EXEMPT"],"example":"STANDARD","description":"VAT rate category"},"vatPercent":{"type":"number","example":17,"description":"VAT percentage"},"trackInventory":{"type":"boolean","example":false},"stockQuantity":{"type":"number","example":50},"lowStockAlert":{"type":"number","example":5,"description":"Alert when stock falls below this number"},"categoryId":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"images":{"example":["https://cdn.example.com/product1.jpg"],"type":"array","items":{"type":"string"}},"isForSale":{"type":"boolean","example":true},"isForInvoice":{"type":"boolean","example":true},"weight":{"type":"number","example":0.1,"description":"Weight in kg"},"packageLength":{"type":"number","example":20,"description":"Package length in cm"},"packageWidth":{"type":"number","example":15,"description":"Package width in cm"},"packageHeight":{"type":"number","example":8,"description":"Package height in cm"},"sizeVariant":{"type":"string","example":"500ml","description":"Size / variant metadata (free text)"},"highlights":{"example":["Long-lasting matte finish","Vegan & cruelty-free"],"description":"Short benefit bullets shown as the marketplace \"Highlights\" card","type":"array","items":{"type":"string"}},"ingredients":{"example":["Aqua","Glycerin","Aloe Vera"],"description":"Ingredient / INCI list shown as the marketplace \"Ingredients\" card","type":"array","items":{"type":"string"}},"tags":{"example":["bestseller","new"],"description":"Product tags","type":"array","items":{"type":"string"}},"vendor":{"type":"string","example":"Brand XYZ","description":"Vendor/brand name"},"productType":{"type":"string","example":"Hair Care","description":"Product type"},"compareAtPrice":{"type":"number","example":24.99,"description":"Compare-at price (was price)"},"isOnline":{"type":"boolean","example":false,"description":"Available in online shop"},"status":{"type":"string","enum":["ACTIVE","DRAFT","UNLISTED","ARCHIVED","INACTIVE","OUT_OF_STOCK"],"example":"ACTIVE"},"seoTitle":{"type":"string","example":"Professional Hair Wax","description":"SEO title"},"seoDescription":{"type":"string","example":"Best professional hair wax...","description":"SEO description"},"sellsToCountries":{"example":["LU","DE"],"description":"ISO-2 country codes this product ships to. Empty = inherit the shop's default countries; non-empty overrides the shop.","type":"array","items":{"type":"string"}}},"required":["name","sellingPrice"]},"UpdateProductDto":{"type":"object","properties":{"name":{"type":"string","example":"Hair Wax Matte Finish"},"description":{"type":"string","example":"Professional hair wax with matte finish, 100ml"},"sku":{"type":"string","example":"HW-MATTE-100"},"ean":{"type":"string","example":"5901234123457"},"purchasePrice":{"type":"number","example":8.5},"sellingPrice":{"type":"number","example":18.99},"vatRate":{"type":"string","enum":["STANDARD","REDUCED","SUPER_REDUCED","ZERO","EXEMPT"],"example":"STANDARD","description":"VAT rate category"},"vatPercent":{"type":"number","example":17,"description":"VAT percentage"},"trackInventory":{"type":"boolean","example":false},"stockQuantity":{"type":"number","example":50},"lowStockAlert":{"type":"number","example":5,"description":"Alert when stock falls below this number"},"categoryId":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"images":{"example":["https://cdn.example.com/product1.jpg"],"type":"array","items":{"type":"string"}},"isForSale":{"type":"boolean","example":true},"isForInvoice":{"type":"boolean","example":true},"weight":{"type":"number","example":0.1,"description":"Weight in kg"},"packageLength":{"type":"number","example":20,"description":"Package length in cm"},"packageWidth":{"type":"number","example":15,"description":"Package width in cm"},"packageHeight":{"type":"number","example":8,"description":"Package height in cm"},"sizeVariant":{"type":"string","example":"500ml","description":"Size / variant metadata (free text)"},"highlights":{"example":["Long-lasting matte finish","Vegan & cruelty-free"],"description":"Short benefit bullets shown as the marketplace \"Highlights\" card","type":"array","items":{"type":"string"}},"ingredients":{"example":["Aqua","Glycerin","Aloe Vera"],"description":"Ingredient / INCI list shown as the marketplace \"Ingredients\" card","type":"array","items":{"type":"string"}},"tags":{"example":["bestseller","new"],"description":"Product tags","type":"array","items":{"type":"string"}},"vendor":{"type":"string","example":"Brand XYZ","description":"Vendor/brand name"},"productType":{"type":"string","example":"Hair Care","description":"Product type"},"compareAtPrice":{"type":"number","example":24.99,"description":"Compare-at price (was price)"},"isOnline":{"type":"boolean","example":false,"description":"Available in online shop"},"status":{"type":"string","enum":["ACTIVE","DRAFT","UNLISTED","ARCHIVED","INACTIVE","OUT_OF_STOCK"],"example":"ACTIVE"},"seoTitle":{"type":"string","example":"Professional Hair Wax","description":"SEO title"},"seoDescription":{"type":"string","example":"Best professional hair wax...","description":"SEO description"},"sellsToCountries":{"example":["LU","DE"],"description":"ISO-2 country codes this product ships to. Empty = inherit the shop's default countries; non-empty overrides the shop.","type":"array","items":{"type":"string"}}}},"AdjustInventoryDto":{"type":"object","properties":{"changeQty":{"type":"number","example":10,"description":"Quantity change (positive to add, negative to remove)"},"reason":{"type":"string","example":"Restocked from supplier"}},"required":["changeQty"]},"BookingServiceDto":{"type":"object","properties":{"serviceId":{"type":"string"},"variantId":{"type":"string"},"addons":{"type":"array","items":{"$ref":"#/components/schemas/BookingAddonDto"}}},"required":["serviceId"]},"BookingAddonDto":{"type":"object","properties":{"addonId":{"type":"string"}},"required":["addonId"]}},"securitySchemes":{"JWT-auth":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"JWT","description":"Enter JWT token","in":"header"},"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Salonify API key (sk_live_...). Each endpoint lists the scope it requires."}}},"security":[{"ApiKey":[]}]}}