{"openapi":"3.1.0","info":{"title":"Bronjoy","version":"0.0.1"},"servers":[{"url":"https://api.bronjoy.com/api"}],"paths":{"/org/announcements":{"get":{"operationId":"announcements.index","summary":"List announcements for the organization","tags":["Announcement"],"parameters":[{"name":"active","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Paginated set of `AnnouncementResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AnnouncementResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"announcements.store","summary":"Create a new announcement","tags":["Announcement"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAnnouncementRequest"}}}},"responses":{"200":{"description":"`AnnouncementResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AnnouncementResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/announcements/{announcement}":{"get":{"operationId":"announcements.show","summary":"Get a single announcement","tags":["Announcement"],"parameters":[{"name":"announcement","in":"path","required":true,"description":"The announcement ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`AnnouncementResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AnnouncementResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"announcements.update","summary":"Update an announcement","tags":["Announcement"],"parameters":[{"name":"announcement","in":"path","required":true,"description":"The announcement ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAnnouncementRequest"}}}},"responses":{"200":{"description":"`AnnouncementResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AnnouncementResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"announcements.destroy","summary":"Delete an announcement","tags":["Announcement"],"parameters":[{"name":"announcement","in":"path","required":true,"description":"The announcement ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Announcement deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/appointments":{"get":{"operationId":"appointment.index","tags":["Appointment"],"parameters":[{"name":"status[]","in":"query","schema":{"type":"array","enum":["pending","confirmed","completed","cancelled","no_show"],"items":{"type":"string","enum":["pending","confirmed","completed","cancelled","no_show"]}}},{"name":"payment_status[]","in":"query","schema":{"type":"array","enum":["unpaid","paid","refunded"],"items":{"type":"string","enum":["unpaid","paid","refunded"]}}},{"name":"staff_id[]","in":"query","schema":{"type":"array","items":{"type":"integer"}}},{"name":"service_id[]","in":"query","schema":{"type":"array","items":{"type":"integer"}}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"my_appointments","in":"query","schema":{"type":["boolean","null"]}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":1000}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["id","start_time","status","payment_status","created_at"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated set of `AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"post":{"operationId":"appointment.store","tags":["Appointment"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/appointments/pending":{"get":{"operationId":"appointment.pending","tags":["Appointment"],"parameters":[{"name":"per_page","in":"query","schema":{"type":"string","default":20}}],"responses":{"200":{"description":"Paginated set of `AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/appointments/calendar":{"get":{"operationId":"appointment.calendar","tags":["Appointment"],"parameters":[{"name":"start","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Array of `AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/appointments/batch-update":{"post":{"operationId":"appointment.batchUpdate","tags":["Appointment"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateAppointmentsRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"updated_count":{"type":"string"}},"required":["message","updated_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/appointments/batch-destroy":{"post":{"operationId":"appointment.batchDestroy","tags":["Appointment"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDestroyAppointmentsRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"deleted_count":{"type":"string"}},"required":["message","deleted_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/appointments/{appointment}":{"get":{"operationId":"appointment.show","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"appointment.update","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"appointment.destroy","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Appointment deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/appointments/{appointment}/submit":{"post":{"operationId":"appointment.submit","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/appointments/{appointment}/cancel":{"post":{"operationId":"appointment.cancel","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/appointments/{appointment}/reschedule":{"post":{"operationId":"appointment.reschedule","tags":["Appointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/schedule":{"get":{"operationId":"availability.schedule","summary":"Get unified schedule - both recurring availabilities and one-time exceptions\nSupports my_schedule=true to filter to current user's schedule only","tags":["Availability"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"string"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"availability.store","summary":"Store a new schedule entry","tags":["Availability"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreScheduleEntryRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]},"message":{"type":"string","enum":["One-time availability created"]}},"required":["data","message"]},{"type":"object","properties":{"data":{"type":"array","prefixItems":[{"type":"object","properties":{"id":{"type":"string"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]}],"minItems":1,"maxItems":1,"additionalItems":false},"message":{"type":"string","enum":["Recurring availability created"]}},"required":["data","message"]}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/schedule/{id}":{"put":{"operationId":"availability.update","summary":"Update a schedule entry","tags":["Availability"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateScheduleEntryRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Exception updated"]},"data":{"type":"object","properties":{"id":{"type":"integer"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]}},"required":["message","data"]},{"type":"object","properties":{"message":{"type":"string","enum":["Availability updated"]},"data":{"type":"object","properties":{"id":{"type":"integer"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]}},"required":["message","data"]},{"type":"object","properties":{"message":{"type":"string","enum":["Converted to recurring availability"]},"data":{"type":"object","properties":{"id":{"type":"string"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]}},"required":["message","data"]},{"type":"object","properties":{"message":{"type":"string","enum":["Converted to one-time availability"]},"data":{"type":"object","properties":{"id":{"type":"string"},"is_recurring":{"type":"boolean"}},"required":["id","is_recurring"]}},"required":["message","data"]}]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["day_of_week is required for recurring entries"]}},"required":["error"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Entry not found"]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"availability.destroy","summary":"Delete a schedule entry","tags":["Availability"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"is_recurring","in":"query","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Availability deleted","Exception deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Entry not found"]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/availability":{"get":{"operationId":"availability.index","tags":["Availability"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"availability.legacyUpdate","tags":["Availability"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"availabilities":{"type":"array","items":{"type":"object","properties":{"staff_id":{"type":["integer","null"]},"service_id":{"type":["integer","null"]},"day_of_week":{"type":"integer","minimum":0,"maximum":6},"start_time":{"type":"string"},"end_time":{"type":"string"},"is_available":{"type":"boolean"}},"required":["day_of_week","start_time","end_time"]}}},"required":["availabilities"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","prefixItems":[{"type":"string"}],"minItems":1,"maxItems":1,"additionalItems":false},"message":{"type":"string","enum":["Availability updated"]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/availability/exceptions":{"get":{"operationId":"availability.exceptions","tags":["Availability"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"availability.storeException","tags":["Availability"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"staff_id":{"type":["integer","null"]},"service_id":{"type":["integer","null"]},"date":{"type":"string","format":"date"},"start_time":{"type":["string","null"]},"end_time":{"type":["string","null"]},"is_available":{"type":"boolean"},"reason":{"type":["string","null"],"maxLength":255}},"required":["date"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/organization-profiles/{slug}/booking-requests":{"post":{"operationId":"bookingRequest.store","description":"Unclaimed venues only: Bronjoy passes the request on to the venue by\nphone. A claimed venue answers 409 — it has real online booking. The same\nphone asking for the same venue again within 24 hours gets the first\nrequest back (200) instead of a duplicate.\n\nPublic endpoint, published profiles only. Guarded by Turnstile (when\nconfigured) and the `booking-request` limiter.","summary":"Leave a booking request on a venue that takes no online bookings yet","tags":["BookingRequest"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitBookingRequestRequest"}}}},"responses":{"201":{"description":"201 for a new request; 200 when a duplicate returns the first one.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["new","forwarded","booked","no_answer","declined","spam"]},"telegram_ref":{"type":"string"}},"required":["id","status","telegram_ref"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/branches":{"get":{"operationId":"branches.index","tags":["Branch"],"responses":{"200":{"description":"Paginated set of `BranchResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BranchResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"branches.store","tags":["Branch"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBranchRequest"}}}},"responses":{"200":{"description":"`BranchResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BranchResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"upgrade_required":{"type":"boolean"}},"required":["message","upgrade_required"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/branches/{branch}":{"get":{"operationId":"branches.show","tags":["Branch"],"parameters":[{"name":"branch","in":"path","required":true,"description":"The branch ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`BranchResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BranchResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"branches.update","tags":["Branch"],"parameters":[{"name":"branch","in":"path","required":true,"description":"The branch ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBranchRequest"}}}},"responses":{"200":{"description":"`BranchResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BranchResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"branches.destroy","tags":["Branch"],"parameters":[{"name":"branch","in":"path","required":true,"description":"The branch ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/calendar/callback/google":{"get":{"operationId":"calendar.callback.google","summary":"Handle Google OAuth callback.\nExchanges authorization code for tokens and redirects back to frontend","tags":["CalendarCallback"],"parameters":[{"name":"code","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/org/calendar/connections":{"get":{"operationId":"calendarConnection.index","summary":"List the current staff member's calendar connections","tags":["CalendarConnection"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CalendarConnectionResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff profile not found."]}},"required":["message"]}}}}}}},"/org/calendar/auth-url":{"get":{"operationId":"calendarConnection.getAuthUrl","summary":"Generate the OAuth authorization URL for connecting a provider","tags":["CalendarConnection"],"parameters":[{"name":"provider","in":"query","schema":{"type":"string","default":"google"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":["string","null"]}},"required":["url"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff profile not found."]}},"required":["message"]}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Unsupported calendar provider."]}},"required":["message"]}}}}}}},"/org/calendar/feed-url":{"get":{"operationId":"calendarConnection.getFeedUrl","summary":"Get the iCal feed URL for the current staff member","tags":["CalendarConnection"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"feed_url":{"type":"string"}},"required":["feed_url"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff profile not found."]}},"required":["message"]}}}}}}},"/org/calendar/connections/{connection}":{"delete":{"operationId":"calendarConnection.disconnect","summary":"Disconnect a calendar connection and revoke tokens","tags":["CalendarConnection"],"parameters":[{"name":"connection","in":"path","required":true,"description":"The connection ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Calendar disconnected."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Not authorized."]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/calendar/connections/{connection}/toggle":{"patch":{"operationId":"calendarConnection.toggleSync","summary":"Toggle push or pull sync for a connection","tags":["CalendarConnection"],"parameters":[{"name":"connection","in":"path","required":true,"description":"The connection ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CalendarConnectionResource"},"message":{"type":"string","enum":["Sync settings updated."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Not authorized."]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/calendar/connections/{connection}/sync":{"post":{"operationId":"calendarConnection.syncNow","summary":"Trigger an immediate sync for a calendar connection","tags":["CalendarConnection"],"parameters":[{"name":"connection","in":"path","required":true,"description":"The connection ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Sync queued."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Not authorized."]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/calendar/feed/{token}.ics":{"get":{"operationId":"calendar.feed","summary":"Serve the iCal feed for a staff member.\nThe token in the URL authenticates the request — no login needed","tags":["CalendarFeed"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"text/calendar; charset=utf-8":{"schema":{"type":"string"}}},"headers":{"Content-Disposition":{"schema":{"type":"string","enum":["attachment; filename=\"bronjoy-calendar.ics\""]}},"Cache-Control":{"schema":{"type":"string","enum":["no-cache, must-revalidate"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/categories":{"get":{"operationId":"categories.index","summary":"List all categories with published organization counts and metadata.\nUsed for the /categories index page","tags":["CategoryLanding"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]},"cover_image":{"type":["string","null"]},"organizations_count":{"type":"integer"},"parent":{"type":["object","null"],"properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":"string"}},"required":["slug","locale_slug","name","icon"]}},"required":["slug","locale_slug","name","icon","illustration","cover_image","organizations_count","parent"]}}}}}}}},"/categories/{slug}":{"get":{"operationId":"categories.show","description":"Responds 301 (with a `Location` header) when the requested slug is one\nthe category has been renamed away from rather than its current slug.","summary":"Get category landing page data: category details, city breakdown, sibling categories","tags":["CategoryLanding"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"object","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"locale_slugs":{"type":"object","additionalProperties":{"type":"string"}},"name":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]},"cover_image":{"type":["string","null"]},"parent":{"type":["object","null"],"properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":"string"}},"required":["slug","locale_slug","name","icon"]}},"required":["slug","locale_slug","locale_slugs","name","icon","illustration","cover_image","parent"]},"total_organizations":{"type":"integer"},"cities":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"count":{"type":"integer"}},"required":["name","slug","count"]}},"siblings":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]},"organizations_count":{"type":"integer"}},"required":["slug","locale_slug","name","icon","organizations_count"]}}},"required":["category","total_organizations","cities","siblings"]}}}},"301":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"redirect_to":{"type":"string"}},"required":["redirect_to"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/categories/{slug}/{city}":{"get":{"operationId":"categories.show-city","description":"Responds 301 (with a `Location` header) when the requested category slug\nis one the category has been renamed away from rather than its current\nslug.","summary":"Get category + city landing page data","tags":["CategoryLanding"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"city","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"object","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"locale_slugs":{"type":"object","additionalProperties":{"type":"string"}},"name":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]},"cover_image":{"type":["string","null"]},"parent":{"type":["object","null"],"properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":"string"}},"required":["slug","locale_slug","name","icon"]}},"required":["slug","locale_slug","locale_slugs","name","icon","illustration","cover_image","parent"]},"city":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"}},"required":["name","slug"]},"total_organizations":{"type":"integer"},"facts":{"type":"object","description":"Counted facts the hub's copy may state — see HubFacts.","properties":{"bookable":{"type":"integer"},"priced":{"type":"integer"},"price_min":{"type":["number","null"]},"price_max":{"type":["number","null"]},"open_24h":{"type":"integer"},"with_phone":{"type":"integer"},"top_services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"]}},"open_24h_venues":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"}},"required":["name","path"]}},"spotlight":{"type":["object","null"],"properties":{"name":{"type":"string"},"count":{"type":"integer"},"venues":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"}},"required":["name","path"]}}},"required":["name","count","venues"]}},"required":["bookable","priced","price_min","price_max","open_24h","with_phone","top_services","open_24h_venues","spotlight"]},"other_cities":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"count":{"type":"integer"}},"required":["name","slug","count"]}},"siblings_in_city":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]},"organizations_count":{"type":"integer"}},"required":["slug","locale_slug","name","icon","organizations_count"]}}},"required":["category","city","total_organizations","facts","other_cities","siblings_in_city"]}}}},"301":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"redirect_to":{"type":"string"}},"required":["redirect_to"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/ai/conversations":{"get":{"operationId":"chat.conversations","tags":["Chat"],"responses":{"200":{"description":"Paginated set of `App.Http.Resources.Api.Ai.ConversationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/App.Http.Resources.Api.Ai.ConversationResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/org/ai/conversations/{conversation}":{"get":{"operationId":"chat.show","tags":["Chat"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"`App.Http.Resources.Api.Ai.ConversationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/App.Http.Resources.Api.Ai.ConversationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"delete":{"operationId":"chat.destroy","tags":["Chat"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Conversation deleted."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/ai/chat":{"post":{"operationId":"chat.send","summary":"SSE streaming chat endpoint","tags":["Chat"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","maxLength":5000},"conversation_id":{"type":["string","null"],"format":"uuid"}},"required":["message"]}}}},"responses":{"200":{"description":"Manual echo-based streaming for Swoole/Octane compatibility.\nThe default generator-based response()->stream() with yield\ndoesn't work with Swoole's ob_start capture mechanism.","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"Transfer-Encoding":{"required":true,"schema":{"type":"string","enum":["chunked"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"},"429":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Failed to process your message. Please try again."]}},"required":["message"]}}}}}}},"/cities":{"get":{"operationId":"cityLanding.index","summary":"List all cities that have at least one published organization, with counts.\nUsed for the /cities index page and the sitemap. Ordered by org count desc","tags":["CityLanding"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"organizations_count":{"type":"integer"}},"required":["name","slug","organizations_count"]}}},"required":["data"]}}}}}}},"/cities/{city}":{"get":{"operationId":"cityLanding.show","summary":"City landing page data: the city, its category breakdown, and top providers.\nThe inverse of CategoryLandingController@showCity — \"city → its categories + top providers\"","tags":["CityLanding"],"parameters":[{"name":"city","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"city":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"}},"required":["name","slug"]},"total_organizations":{"type":"integer"},"categories":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"locale_slug":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]},"count":{"type":"integer"}},"required":["name","slug","locale_slug","icon","illustration","count"]}},"top_providers":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationProfileResource"}}},"required":["city","total_organizations","categories","top_providers"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/claims":{"get":{"operationId":"claimRequest.index","summary":"List the authenticated user's claim requests","tags":["ClaimRequest"],"responses":{"200":{"description":"Array of `ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClaimRequestResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"claimRequest.store","summary":"Submit a new claim request","tags":["ClaimRequest"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/StoreClaimRequest"}}}},"responses":{"201":{"description":"`ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimRequestResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/claims/{claimRequest}":{"get":{"operationId":"claimRequest.show","summary":"Show a single claim request belonging to the authenticated user","tags":["ClaimRequest"],"parameters":[{"name":"claimRequest","in":"path","required":true,"description":"The claim request ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimRequestResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/claims/{claimRequest}/documents":{"post":{"operationId":"claimRequest.addDocuments","summary":"Attach additional documents to an open claim request","tags":["ClaimRequest"],"parameters":[{"name":"claimRequest","in":"path","required":true,"description":"The claim request ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/AddClaimDocumentsRequest"}}}},"responses":{"200":{"description":"`ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimRequestResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/claims/{claimRequest}/withdraw":{"post":{"operationId":"claimRequest.withdraw","summary":"Withdraw a pending claim request","tags":["ClaimRequest"],"parameters":[{"name":"claimRequest","in":"path","required":true,"description":"The claim request ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimRequestResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/claims/{claimRequest}/seen":{"post":{"operationId":"claimRequest.markSeen","summary":"Mark a request as seen (clears red-dot indicator)","tags":["ClaimRequest"],"parameters":[{"name":"claimRequest","in":"path","required":true,"description":"The claim request ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ClaimRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimRequestResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/claims/{claimRequest}/telegram-link":{"post":{"operationId":"claimRequest.telegramLink","summary":"A one-time link into the Bronjoy business bot that connects the\napplicant's Telegram, so claim updates reach them there and they can\nsend documents straight to the chat. Valid for 7 days, single use","tags":["ClaimRequest"],"parameters":[{"name":"claimRequest","in":"path","required":true,"description":"The claim request ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"linked":{"type":"boolean"}},"required":["url","linked"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/payment/click/callback":{"post":{"operationId":"clickCallback.handle","tags":["ClickCallback"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"click_trans_id":{"type":"string"},"merchant_trans_id":{"type":"string"},"action":{"type":"string"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"click_trans_id":{"type":"integer"},"merchant_trans_id":{"type":"string"},"merchant_prepare_id":{"type":"integer"},"error":{"type":"string"},"error_note":{"type":"string","enum":["Internal server error"]}},"required":["click_trans_id","merchant_trans_id","merchant_prepare_id","error","error_note"]},{"type":"string"}]}}}}}}},"/org/clients/batch-update":{"post":{"operationId":"client.batchUpdate","summary":"Batch update clients","tags":["Client"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateClientsRequest"}}}},"responses":{"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/clients/batch-destroy":{"post":{"operationId":"client.batchDestroy","summary":"Batch delete clients","tags":["Client"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDestroyClientsRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"deleted_count":{"type":"string"}},"required":["message","deleted_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/clients":{"get":{"operationId":"clients.index","summary":"List the organization's clients (paginated), with visit counts and last/next visit","tags":["Client"],"parameters":[{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"has_upcoming","in":"query","schema":{"type":["boolean","null"]}},{"name":"min_visits","in":"query","schema":{"type":["integer","null"],"minimum":0}},{"name":"max_visits","in":"query","schema":{"type":["integer","null"],"minimum":0}},{"name":"last_visit_from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"last_visit_to","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["id","name","email","created_at","appointments_count","last_visit"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated set of `ClientResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClientResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"post":{"operationId":"clients.store","summary":"Create a client","tags":["Client"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientRequest"}}}},"responses":{"200":{"description":"`ClientResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClientResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/clients/{client}":{"get":{"operationId":"clients.show","summary":"Show a client. Visit history lives on `GET /org/clients/{client}/history`","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ClientResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClientResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"clients.update","summary":"Update a client","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClientRequest"}}}},"responses":{"200":{"description":"`ClientResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClientResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"clients.destroy","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Client deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/clients/{client}/notes":{"get":{"operationId":"client.notes","summary":"Get notes for a client","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"post":{"operationId":"client.storeNote","summary":"Store a note for a client","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreClientNoteRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/clients/{client}/history":{"get":{"operationId":"client.history","summary":"Get appointment history for a client","tags":["Client"],"parameters":[{"name":"client","in":"path","required":true,"description":"The client ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/appointments/{appointment}/cancel-by-token":{"post":{"operationId":"clientAppointment.cancelByToken","summary":"Cancel an appointment using a signed token from a reminder email.\nPublic endpoint — no authentication required","tags":["ClientAppointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"reason":{"type":"string","description":"No invented English reason: it was shown to the salon as the client's."}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Appointment cancelled successfully."]}},"required":["message"]}}}},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invalid or expired cancel link."]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Appointment is already cancelled or completed."]}},"required":["message"]}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Failed to cancel appointment."]}},"required":["message"]}}}}}}},"/appointments/{appointment}/confirm-by-token":{"post":{"operationId":"clientAppointment.confirmByToken","summary":"Confirm an appointment using a signed token.\nPublic endpoint — used when staff manually creates an appointment and sends\nthe client a confirm link","tags":["ClientAppointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Appointment confirmed successfully."]}},"required":["message"]},{"type":"object","properties":{"message":{"type":"string","enum":["Appointment is already confirmed."]}},"required":["message"]}]}}}},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invalid or expired confirmation link."]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Appointment can no longer be confirmed."]}},"required":["message"]}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Failed to confirm appointment."]}},"required":["message"]}}}}}}},"/client/appointments/upcoming":{"get":{"operationId":"clientAppointment.upcoming","summary":"Get upcoming appointments for the authenticated client","tags":["ClientAppointment"],"parameters":[{"name":"organization_id","in":"query","schema":{"type":["integer","null"]}},{"name":"status","in":"query","schema":{"type":["string","null"],"enum":["pending","confirmed","cancelled","completed"]}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/appointments/history":{"get":{"operationId":"clientAppointment.history","summary":"Get past appointments (history) for the authenticated client","tags":["ClientAppointment"],"parameters":[{"name":"organization_id","in":"query","schema":{"type":["integer","null"]}},{"name":"status","in":"query","schema":{"type":["string","null"],"enum":["pending","confirmed","cancelled","completed"]}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/appointments/stats":{"get":{"operationId":"clientAppointment.stats","summary":"Get appointment statistics for the client","tags":["ClientAppointment"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"total_appointments":{"type":"string"},"upcoming":{"type":"string"},"completed":{"type":"string"},"cancelled":{"type":"string"},"organizations_visited":{"type":"string"},"reviews_given":{"type":"string"}},"required":["total_appointments","upcoming","completed","cancelled","organizations_visited","reviews_given"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/appointments/{appointment}":{"get":{"operationId":"clientAppointment.show","summary":"Get a single appointment detail","tags":["ClientAppointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/appointments/{appointment}/cancel":{"post":{"operationId":"clientAppointment.cancel","summary":"Cancel an appointment","tags":["ClientAppointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/App.Http.Requests.Api.Client.CancelAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/appointments/{appointment}/reschedule":{"post":{"operationId":"clientAppointment.reschedule","summary":"Reschedule an appointment","tags":["ClientAppointment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/App.Http.Requests.Api.Client.RescheduleAppointmentRequest"}}}},"responses":{"200":{"description":"`AppointmentResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppointmentResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/auth/phone/request":{"post":{"operationId":"clientAuth.requestPhone","summary":"Request phone verification code for client.\nClients can register/login via phone","tags":["ClientAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestPhoneRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Verification code sent to your phone"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"anyOf":[{"type":"string"},{"type":"string","enum":["123456"]}]}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message",null]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/auth/phone/verify":{"post":{"operationId":"clientAuth.verifyPhone","summary":"Verify phone and login/register client.\nAuto-creates user if doesn't exist","tags":["ClientAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyPhoneRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"user":{"type":"string"}},"required":["access_token","token_type","user"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/auth/email/request":{"post":{"operationId":"clientAuth.requestEmail","summary":"Request email verification code for client.\nClients can register/login via email","tags":["ClientAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestEmailRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Verification code sent to your email"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"anyOf":[{"type":"string"},{"type":"string","enum":["123456"]}]}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message",null]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/auth/email/verify":{"post":{"operationId":"clientAuth.verifyEmail","summary":"Verify email and login/register client.\nAuto-creates user if doesn't exist","tags":["ClientAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"user":{"type":"string"}},"required":["access_token","token_type","user"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/auth/telegram":{"post":{"operationId":"clientAuth.telegram","summary":"Authenticate client via Telegram Mini App.\nAuto-creates user if doesn't exist","tags":["ClientAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramAuthRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"user":{"type":"string"}},"required":["access_token","token_type","user"]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invalid Telegram user data"]}},"required":["message"]}}}},"401":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invalid Telegram authentication data"]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}":{"get":{"operationId":"clientBooking.getOrganizationPage","summary":"Get organization public page with services and staff.\nPublic endpoint - no auth required","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"`OrganizationPublicResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationPublicResource"}},"required":["data"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/booking/{slug}/services":{"get":{"operationId":"clientBooking.getServicesWithStaff","summary":"Get services with their available staff for an organization","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"string"}},"required":["services"]}}}}}}},"/booking/{slug}/staff":{"get":{"operationId":"clientBooking.getStaffWithServices","summary":"Get staff with their services for an organization","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"staff":{"type":"string"}},"required":["staff"]}}}}}}},"/booking/{slug}/slots":{"get":{"operationId":"clientBooking.getAvailableSlots","summary":"Get available slots for a service.\nCan be used by unauthenticated users to view availability","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string"},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"duration":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"slots":{"type":"array","items":{"$ref":"#/components/schemas/SlotResource"}}},"required":["date","service","staff","slots"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}/slots/range":{"get":{"operationId":"clientBooking.getAvailableSlotsRange","summary":"Get available slots for multiple days","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"start_date":{"type":"string"},"end_date":{"type":"string"},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"duration":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"slots_by_date":{"type":"string"}},"required":["start_date","end_date","service","staff","slots_by_date"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}/slots/all":{"get":{"operationId":"clientBooking.getAllSlotsWithStatus","summary":"Get all slots for a date with availability status.\nIncludes both available and booked slots","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string"},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"duration":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"slots":{"type":"array","items":{"$ref":"#/components/schemas/SlotResource"}}},"required":["date","service","staff","slots"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}/slots/grid":{"get":{"operationId":"clientBooking.getSlotsGrid","summary":"Get available slots for all staff members in a grid layout.\nReturns slots grouped by staff and date for a Zocdoc-style availability grid","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"start_date":{"type":"string"},"end_date":{"type":"string"},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"duration":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":"string"},"grid":{"type":"string"}},"required":["start_date","end_date","service","staff","grid"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}/calendar":{"get":{"operationId":"clientBooking.getCalendarAvailability","summary":"Get calendar availability info for a date range.\nReturns date availability status for the booking calendar","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"start_date":{"type":"string"},"end_date":{"type":"string"},"dates":{"type":"object"}},"required":["start_date","end_date","dates"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/booking/{slug}/waitlist/count":{"get":{"operationId":"clientBooking.waitlistCount","summary":"Get waitlist count for a service on a specific date.\nPublic endpoint","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/booking/{slug}/request-code":{"post":{"operationId":"clientBooking.requestCode","description":"Step one of verify-then-book: the caller proves the phone/email is\ntheirs BEFORE `book()` will create anything. Authenticated clients and\nTelegram Mini App users skip this entirely — they are already identified.\n\nPublic endpoint. Protected by Turnstile (dormant until keys are set),\nthe `booking` limiter, and OtpGuard's per-contact send cap.","summary":"Send a confirmation code for a guest booking","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestBookingCodeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"channel":{"type":"string"},"target":{"type":"string"},"expires_in_minutes":{"type":"integer"},"debug_code":{"type":"string"}},"required":["message","channel","target","expires_in_minutes"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/booking/{slug}":{"post":{"operationId":"clientBooking.book","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookAppointmentRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"appointment":{"$ref":"#/components/schemas/AppointmentResource"},"user":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]}},"required":["id","name","phone","email"]},"verification_needed":{"type":"boolean"},"verification_type":{"type":"string"},"payment":{"anyOf":[{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"integer"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"anyOf":[{"type":"integer"},{"type":"integer","enum":[100]}]},"providers":{"type":"string"},"refund_on_cancellation":{"type":"string"},"refund_deadline_hours":{"type":"string"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]},{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"null"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"type":"integer","enum":[0]},"providers":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"refund_on_cancellation":{"type":"boolean"},"refund_deadline_hours":{"type":"null"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]}]},"payment_expires_at":{"type":"string"},"access_token":{"type":"string"},"verification_target":{"type":["string","null"]}},"required":["message","appointment","user","verification_needed","verification_type","payment","payment_expires_at","access_token","verification_target"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/booking/{slug}/waitlist":{"post":{"operationId":"clientBooking.joinWaitlist","summary":"Join the waitlist for a service on a specific date.\nSupports authenticated clients, guest phone/email, and Telegram","tags":["ClientBooking"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinWaitlistRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["You have been added to the waitlist."]},"entry":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"required":["message","entry"]}}}},"401":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Authentication required to join the waitlist."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/appointments/{appointment}/ics":{"get":{"operationId":"client.appointments.ics","summary":"Download a .ics file for a specific appointment","tags":["ClientCalendar"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"text/calendar; charset=utf-8":{"schema":{"type":"string"}}},"headers":{"Content-Disposition":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/appointments/{appointment}/calendar-links":{"get":{"operationId":"clientCalendar.calendarLinks","summary":"Get Google Calendar and Outlook deep-link URLs for an appointment","tags":["ClientCalendar"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"google":{"type":"string"},"outlook":{"type":"string"},"ics_url":{"type":"string"}},"required":["google","outlook","ics_url"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/conversations":{"get":{"operationId":"clientConversation.index","summary":"Get all conversations for the client","tags":["ClientConversation"],"parameters":[{"name":"status","in":"query","schema":{"type":["string","null"],"enum":["active","closed"]}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `ConversationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/conversations/start":{"post":{"operationId":"clientConversation.startOrGet","summary":"Start or get existing conversation with an organization","tags":["ClientConversation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartOrGetConversationRequest"}}}},"responses":{"200":{"description":"`ConversationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConversationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/conversations/{conversation}":{"get":{"operationId":"clientConversation.show","summary":"Get a specific conversation","tags":["ClientConversation"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ConversationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConversationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/conversations/{conversation}/messages":{"get":{"operationId":"clientConversation.messages","summary":"Get messages for a conversation","tags":["ClientConversation"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"string","default":50}}],"responses":{"200":{"description":"Paginated set of `MessageResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MessageResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"post":{"operationId":"clientConversation.sendMessage","summary":"Send a message in a conversation","tags":["ClientConversation"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}}},"responses":{"200":{"description":"`MessageResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MessageResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/conversations/{conversation}/close":{"post":{"operationId":"clientConversation.close","summary":"Close a conversation","tags":["ClientConversation"],"parameters":[{"name":"conversation","in":"path","required":true,"description":"The conversation ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Conversation closed"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/device-tokens":{"post":{"operationId":"clientDeviceToken.store","description":"The native app calls this on every cold start with the current FCM\nregistration token, so it is idempotent: matching on the token (which is\nunique per install) both refreshes `last_used_at` and re-points the row at\nthe current user when a device changes hands.","summary":"Register this device for push notifications","tags":["ClientDeviceToken"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreDeviceTokenRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"integer"},"platform":{"type":"string"}},"required":["id","platform"]}},"required":["message","data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"clientDeviceToken.destroy","description":"Scoped to the authenticated user so a token cannot be used to delete\nsomeone else's registration. Always reports success — the caller is\nlogging out either way and a missing row is the desired end state.","summary":"Unregister a device (called on logout)","tags":["ClientDeviceToken"],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","maxLength":512}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/favorites":{"get":{"operationId":"clientFavorite.index","summary":"List the authenticated user's favorite organizations","tags":["ClientFavorite"],"parameters":[{"name":"per_page","in":"query","schema":{"type":"string","default":20}}],"responses":{"200":{"description":"Paginated set of `FavoriteResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FavoriteResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/favorites/toggle":{"post":{"operationId":"clientFavorite.toggle","summary":"Toggle favorite status for an organization","tags":["ClientFavorite"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleFavoriteRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Removed from favorites"]},"is_favorited":{"type":"boolean"}},"required":["message","is_favorited"]}}}},"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Added to favorites"]},"is_favorited":{"type":"boolean"}},"required":["message","is_favorited"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/favorites/sync":{"post":{"operationId":"clientFavorite.sync","summary":"Sync favorites from local storage slugs.\nCreates favorites for organizations that aren't already favorited","tags":["ClientFavorite"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncFavoritesRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"synced":{"type":"string"}},"required":["synced"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/favorites/check/{organization}":{"get":{"operationId":"clientFavorite.check","summary":"Check if an organization is favorited by the authenticated user","tags":["ClientFavorite"],"parameters":[{"name":"organization","in":"path","required":true,"description":"The organization ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"is_favorited":{"type":"string"}},"required":["is_favorited"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/notification-settings":{"get":{"operationId":"client.notificationSettings.show","description":"Preferences are stored per-Client (one record per organization). We merge\nthem into a single view: a channel is ON iff it's ON for every Client.","summary":"Get the authenticated user's notification preferences","tags":["ClientNotificationSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClientNotificationSettingResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"client.notificationSettings.update","summary":"Update notification preferences. The same preference set is applied to\nevery Client record owned by the authenticated user","tags":["ClientNotificationSetting"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClientNotificationSettingsRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClientNotificationSettingResource"},"message":{"type":"string","enum":["Notification settings updated."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/payments/appointments/{appointment}/requirement":{"get":{"operationId":"clientPayment.requirement","summary":"Get payment requirement for an appointment the client owns","tags":["ClientPayment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"requirement":{"anyOf":[{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"integer"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"anyOf":[{"type":"integer"},{"type":"integer","enum":[100]}]},"providers":{"type":"string"},"refund_on_cancellation":{"type":"string"},"refund_deadline_hours":{"type":"string"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]},{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"null"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"type":"integer","enum":[0]},"providers":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"refund_on_cancellation":{"type":"boolean"},"refund_deadline_hours":{"type":"null"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]}]},"transactions":{"type":"array","items":{"$ref":"#/components/schemas/PaymentTransactionResource"}}},"required":["requirement","transactions"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"$ref":"#/components/responses/AuthorizationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/payments/appointments/{appointment}/transactions":{"get":{"operationId":"clientPayment.transactions","summary":"List all transactions for an appointment","tags":["ClientPayment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentTransactionResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"$ref":"#/components/responses/AuthorizationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/payments/appointments/{appointment}/pay":{"post":{"operationId":"clientPayment.initiate","summary":"Initiate payment for an appointment.\nAmount is auto-calculated from the prepay policy — client only picks the provider","tags":["ClientPayment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateClientPaymentRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentTransactionResource"},"checkout":{"type":"object","properties":{"url":{"type":"string"},"params":{"type":"object","additionalProperties":{}}},"required":["url"]}},"required":["data","checkout"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"$ref":"#/components/responses/AuthorizationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/payments/transactions/{transaction}":{"get":{"operationId":"clientPayment.status","summary":"Get status of a specific transaction belonging to the client","tags":["ClientPayment"],"parameters":[{"name":"transaction","in":"path","required":true,"description":"The transaction ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentTransactionResource"},"provider_status":{"type":"array","items":{}}},"required":["data","provider_status"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"$ref":"#/components/responses/AuthorizationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/profile":{"get":{"operationId":"clientProfile.show","summary":"Get current user's profile","tags":["ClientProfile"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"telegram_id":{"type":"string"},"locale":{"type":"string"},"email_verified":{"type":"boolean"},"phone_verified":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","name","email","phone","telegram_id","locale","email_verified","phone_verified","created_at"]},"organizations":{"type":"string"}},"required":["user","organizations"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"clientProfile.update","summary":"Update profile (name and non-sensitive fields)","tags":["ClientProfile"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Profile updated successfully"]},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"locale":{"type":"string"}},"required":["id","name","email","phone","locale"]}},"required":["message","user"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"clientProfile.deleteAccount","summary":"Delete account (soft delete)","tags":["ClientProfile"],"parameters":[{"name":"confirm","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Account deleted successfully"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/profile/email/request":{"post":{"operationId":"clientProfile.requestEmailChange","summary":"Request verification code to update email","tags":["ClientProfile"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestEmailChangeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Verification code sent to your new email address"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"type":"string"}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message",null]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/profile/email/verify":{"post":{"operationId":"clientProfile.verifyEmailChange","summary":"Verify and complete email change","tags":["ClientProfile"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailChangeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Email updated successfully"]},"email":{"type":"string"}},"required":["message","email"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/profile/phone/request":{"post":{"operationId":"clientProfile.requestPhoneChange","summary":"Request verification code to update phone","tags":["ClientProfile"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestPhoneChangeRequest"}}}},"responses":{"200":{"description":"TODO: Send SMS verification in production\nSMS::send($validated['new_phone'], \"Your verification code is: {$newCode}\");","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Verification code sent to your new phone number"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"type":"string"}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message",null]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/profile/phone/verify":{"post":{"operationId":"clientProfile.verifyPhoneChange","summary":"Verify and complete phone change","tags":["ClientProfile"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyPhoneChangeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Phone number updated successfully"]},"phone":{"type":"string"}},"required":["message","phone"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/profile/organizations":{"get":{"operationId":"clientProfile.organizations","summary":"Get list of organizations where user is a client","tags":["ClientProfile"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"organizations":{"type":"string"}},"required":["organizations"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/referral":{"get":{"operationId":"client.referral.","description":"The partner profile — referral code, shareable link and earnings summary.\nThe profile is created on first view so the QR is available immediately.","summary":"GET /api/client/referral","tags":["ClientReferral"],"responses":{"200":{"description":"`ReferralPartnerResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReferralPartnerResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/referral/businesses":{"get":{"operationId":"clientReferral.businesses","description":"Businesses this partner has referred, with per-business earnings + status.","summary":"GET /api/client/referral/businesses","tags":["ClientReferral"],"responses":{"200":{"description":"Array of `ReferredBusinessResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReferredBusinessResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/referral/commissions":{"get":{"operationId":"clientReferral.commissions","description":"The earnings ledger — one row per subscription payment commissioned.","summary":"GET /api/client/referral/commissions","tags":["ClientReferral"],"responses":{"200":{"description":"Array of `PartnerCommissionResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PartnerCommissionResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/referral/payout-methods":{"get":{"operationId":"clientReferral.payoutMethods","summary":"GET /api/client/referral/payout-methods","tags":["ClientReferral"],"responses":{"200":{"description":"Array of `PartnerPayoutMethodResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PartnerPayoutMethodResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"clientReferral.storePayoutMethod","description":"Connect a card to receive payouts.","summary":"POST /api/client/referral/payout-methods","tags":["ClientReferral"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorePartnerPayoutMethodRequest"}}}},"responses":{"200":{"description":"`PartnerPayoutMethodResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PartnerPayoutMethodResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/referral/payout-methods/{payoutMethod}":{"delete":{"operationId":"clientReferral.destroyPayoutMethod","summary":"DELETE /api/client/referral/payout-methods/{payoutMethod}","tags":["ClientReferral"],"parameters":[{"name":"payoutMethod","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Card removed."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/referral/payouts":{"get":{"operationId":"clientReferral.payouts","summary":"GET /api/client/referral/payouts","tags":["ClientReferral"],"responses":{"200":{"description":"Array of `PartnerPayoutResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PartnerPayoutResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"clientReferral.requestPayout","description":"Request a payout of the available balance (or part of it).","summary":"POST /api/client/referral/payouts","tags":["ClientReferral"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestPartnerPayoutRequest"}}}},"responses":{"200":{"description":"`PartnerPayoutResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PartnerPayoutResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/reviews":{"get":{"operationId":"clientReview.index","summary":"Get reviews left by the client","tags":["ClientReview"],"parameters":[{"name":"organization_id","in":"query","schema":{"type":["integer","null"]}},{"name":"rating","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":5}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `ReviewResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"post":{"operationId":"clientReview.store","summary":"Create a new review for a completed appointment","tags":["ClientReview"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Review submitted successfully"]},"review":{"$ref":"#/components/schemas/ReviewResource"}},"required":["message","review"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/reviews/reviewable":{"get":{"operationId":"clientReview.reviewableAppointments","summary":"Get appointments that can be reviewed","tags":["ClientReview"],"parameters":[{"name":"per_page","in":"query","schema":{"type":"string","default":20}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"reviewable_appointments":{"type":"string"},"pagination":{"type":"object","properties":{"current_page":{"type":"string"},"total_pages":{"type":"string"},"total":{"type":"string"}},"required":["current_page","total_pages","total"]}},"required":["reviewable_appointments","pagination"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/reviews/{review}":{"get":{"operationId":"clientReview.show","summary":"Get a single review","tags":["ClientReview"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ReviewResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReviewResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"clientReview.update","summary":"Update a review","tags":["ClientReview"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviewRequest"}}}},"responses":{"200":{"description":"`ReviewResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReviewResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"clientReview.destroy","summary":"Delete a review","tags":["ClientReview"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Review deleted successfully"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/waitlist":{"get":{"operationId":"clientWaitlist.index","summary":"List the authenticated client's waitlist entries across all organizations","tags":["ClientWaitlist"],"responses":{"200":{"description":"Paginated set of `WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/waitlist/{waitlistEntry}/accept":{"post":{"operationId":"clientWaitlist.accept","summary":"Accept an offered slot — creates the appointment","tags":["ClientWaitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Appointment booked successfully from waitlist."]},"appointment":{"type":"string"}},"required":["message","appointment"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/waitlist/{waitlistEntry}/decline":{"post":{"operationId":"clientWaitlist.decline","summary":"Decline an offered slot","tags":["ClientWaitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Offer declined."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/client/waitlist/{waitlistEntry}/cancel":{"post":{"operationId":"clientWaitlist.cancel","summary":"Cancel a waitlist entry","tags":["ClientWaitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Waitlist entry cancelled."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/auth/me":{"get":{"operationId":"commonAuth.me","summary":"Get the authenticated user's information.\nWorks for both clients and staff","tags":["CommonAuth"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/auth/logout":{"post":{"operationId":"commonAuth.logout","summary":"Logout the authenticated user.\nRevokes the current access token","tags":["CommonAuth"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Logged out successfully"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/auth/me/locale":{"put":{"operationId":"commonAuth.updateLocale","summary":"Update the authenticated user's preferred locale.\nWorks for both clients and staff","tags":["CommonAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locale":{"type":"string","enum":["en","uz","ru"]}},"required":["locale"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"locale":{"type":"string"}},"required":["message","locale"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/auth/me/telegram-link":{"post":{"operationId":"commonAuth.telegramLink","summary":"A one-time link into the business bot that connects this account's Telegram,\nso booking alerts reach it. Valid for 7 days, single use","tags":["CommonAuth"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"linked":{"type":"boolean"}},"required":["url","linked"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/auth/me/platform-notifications":{"put":{"operationId":"commonAuth.updatePlatformNotificationPreferences","description":"These live on the user rather than the organization: someone running\nthree businesses should hear about a maintenance window once. Service\nmessages — incidents, maintenance, policy changes — ignore both flags.","summary":"Update what Bronjoy itself is allowed to send this person on Telegram","tags":["CommonAuth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"telegram_platform_updates_enabled":{"type":"boolean"},"telegram_marketing_enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Platform notification preferences updated."]},"data":{"type":"object","properties":{"telegram_platform_updates_enabled":{"type":"boolean"},"telegram_marketing_enabled":{"type":"boolean"}},"required":["telegram_platform_updates_enabled","telegram_marketing_enabled"]}},"required":["message","data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/dashboard":{"get":{"operationId":"dashboard.index","description":"Returns stats with trend comparisons and daily chart data,\nall filtered by the provided date range.","summary":"Get unified dashboard data for the authenticated organization","tags":["Dashboard"],"parameters":[{"name":"start_date","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"`DashboardResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DashboardResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/geo/cities":{"get":{"operationId":"geo.cities","description":"`latitude` / `longitude` are the median coordinates of the city's existing main\nbranches, not a surveyed centre — they exist so a map picker can open somewhere\nuseful, and are null for a city we have no mapped business in yet. The median\n(rather than the mean) keeps one mis-geocoded listing from dragging the centre\ninto the desert.","summary":"Every city, for the onboarding / settings location picker","tags":["Geo"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"region":{"type":["string","null"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"organizations_count":{"type":"integer"}},"required":["id","slug","name","region","latitude","longitude","organizations_count"]}}},"required":["data"]}}}}}}},"/health":{"get":{"operationId":"health.healthCheckJsonResults","tags":["HealthCheckJsonResults"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/scraper/import":{"post":{"operationId":"import.import","description":"Expects JSON body: { \"businesses\": [...] }\nAuth: Bearer token matching SCRAPER_API_TOKEN env var.","summary":"Import businesses from the scraper","tags":["Import"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"businesses":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"_dedup_key":{"type":"string"}},"required":["name","slug","_dedup_key"]},"minItems":1}},"required":["businesses"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"":{"type":"array","items":{}}},"required":["message",null]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/join-requests/search":{"post":{"operationId":"joinRequest.searchByInviteCode","summary":"Search for an organization by invite code.\nPublic endpoint (but requires auth) for users looking to join","tags":["JoinRequest"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchInviteCodeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"organization":{"$ref":"#/components/schemas/OrganizationResource"},"already_requested":{"type":"boolean"},"already_member":{"type":"string"}},"required":["organization","already_requested","already_member"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Organization not found or is not accepting join requests."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/join-requests":{"post":{"operationId":"joinRequest.store","summary":"Create a join request for an organization","tags":["JoinRequest"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreJoinRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Join request submitted successfully."]},"join_request":{"$ref":"#/components/schemas/StaffJoinRequestResource"}},"required":["message","join_request"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["This organization is not accepting join requests."]}},"required":["message"]}}}},"409":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["You already have a pending request to join this organization."]},"join_request":{"$ref":"#/components/schemas/StaffJoinRequestResource"}},"required":["message","join_request"]},{"type":"object","properties":{"message":{"type":"string","enum":["You are already a member of this organization."]}},"required":["message"]}]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}},"get":{"operationId":"joinRequest.index","summary":"Get pending join requests for the current organization (owner only)","tags":["JoinRequest"],"responses":{"200":{"description":"Array of `StaffJoinRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffJoinRequestResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"An error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview.","example":"Unauthorized"}},"required":["message"]}}}}}}},"/org/join-requests/my":{"get":{"operationId":"joinRequest.myRequests","summary":"Get the current user's join requests","tags":["JoinRequest"],"responses":{"200":{"description":"Array of `StaffJoinRequestResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffJoinRequestResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/join-requests/{joinRequest}":{"delete":{"operationId":"joinRequest.cancel","summary":"Cancel a join request (by the requester)","tags":["JoinRequest"],"parameters":[{"name":"joinRequest","in":"path","required":true,"description":"The join request ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Join request cancelled."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Unauthorized"]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["This request has already been processed."]}},"required":["message"]}}}}}}},"/org/join-requests/{joinRequest}/approve":{"post":{"operationId":"joinRequest.approve","summary":"Approve a join request","tags":["JoinRequest"],"parameters":[{"name":"joinRequest","in":"path","required":true,"description":"The join request ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveJoinRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Join request approved successfully."]},"staff":{"$ref":"#/components/schemas/StaffResource"}},"required":["message","staff"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Unauthorized"]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["This request has already been processed."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/join-requests/{joinRequest}/reject":{"post":{"operationId":"joinRequest.reject","summary":"Reject a join request","tags":["JoinRequest"],"parameters":[{"name":"joinRequest","in":"path","required":true,"description":"The join request ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectJoinRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Join request rejected."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Unauthorized"]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["This request has already been processed."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/ai/tokens":{"post":{"operationId":"mcpToken.store","summary":"Generate a new MCP access token for external AI clients","tags":["McpToken"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"expires_in_days":{"type":["integer","null"],"minimum":1,"maximum":365}},"required":["name"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"mcp_endpoint":{"type":"string"},"expires_at":{"type":"string"},"instructions":{"type":"string","enum":["Use this token in the Authorization header: Bearer <token>"]}},"required":["token","mcp_endpoint","expires_at","instructions"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/media":{"post":{"operationId":"media.store","summary":"Upload a file and return its URL","tags":["Media"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadMediaRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string"}},"required":["path"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["File upload failed"]}},"required":["message"]}}}}}}},"/client/notifications":{"get":{"operationId":"client.notification.index","description":"Takes a FormRequest rather than a bare Request so `per_page` reaches the\nOpenAPI spec — the generated client method is otherwise argument-less and\ncallers cannot page.","summary":"List notifications (paginated) with unread count","tags":["Notification"],"parameters":[{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `NotificationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]},"unread_count":{"type":"string"}},"required":["data","links","meta","unread_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/client/notifications/unread-count":{"get":{"operationId":"client.notification.unreadCount","summary":"Get unread notification count (lightweight endpoint for polling)","tags":["Notification"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"unread_count":{"type":"string"}},"required":["unread_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/notifications/{id}/read":{"post":{"operationId":"client.notification.markAsRead","summary":"Mark a single notification as read","tags":["Notification"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/client/notifications/read-all":{"post":{"operationId":"client.notification.markAllAsRead","summary":"Mark all notifications as read","tags":["Notification"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/notifications":{"get":{"operationId":"org.notification.index","description":"Takes a FormRequest rather than a bare Request so `per_page` reaches the\nOpenAPI spec — the generated client method is otherwise argument-less and\ncallers cannot page.","summary":"List notifications (paginated) with unread count","tags":["Notification"],"parameters":[{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `NotificationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]},"unread_count":{"type":"string"}},"required":["data","links","meta","unread_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/notifications/unread-count":{"get":{"operationId":"org.notification.unreadCount","summary":"Get unread notification count (lightweight endpoint for polling)","tags":["Notification"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"unread_count":{"type":"string"}},"required":["unread_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/notifications/{id}/read":{"post":{"operationId":"org.notification.markAsRead","summary":"Mark a single notification as read","tags":["Notification"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/notifications/read-all":{"post":{"operationId":"org.notification.markAllAsRead","summary":"Mark all notifications as read","tags":["Notification"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/onboarding/maps/providers":{"get":{"operationId":"onboarding.mapProviders","description":"Every provider is listed, with `enabled` telling whether it has credentials on this\nserver. `meta.configured` is false when none of them do — the client must then show an\nexplicit \"map import unavailable\" state and steer the user to manual entry, instead of\nrendering an empty search screen.","summary":"List map import providers and their availability","tags":["Onboarding"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"enabled":{"type":"boolean"}},"required":["provider","enabled"]}},"meta":{"type":"object","properties":{"configured":{"type":"boolean"},"enabled":{"type":"array","items":{"type":"string"}},"enabled_count":{"type":"integer"},"message":{"type":["string","null"]}},"required":["configured","enabled","enabled_count","message"]}},"required":["data","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/onboarding/maps/search":{"post":{"operationId":"onboarding.mapSearch","description":"Returns grouped results keyed by provider so the UI can render side-by-side previews\nbefore the user creates their organization. `meta.status` separates the two failure\nmodes that otherwise look identical to the client:\n- `no_providers` — nothing is configured, searching can never return anything\n- `no_results` — providers were queried and matched no business","summary":"Search across Google / 2GIS / Yandex for businesses matching a query","tags":["Onboarding"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MapSearchRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"data":{"type":"object","additionalProperties":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"meta":{"type":"object","properties":{"status":{"type":"string"},"configured":{"type":"boolean"},"providers_searched":{"type":"array","items":{"type":"string"}},"result_count":{"type":"integer"},"message":{"type":["string","null"]}},"required":["status","configured","providers_searched","result_count","message"]}},"required":["query","data","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/onboarding/complete":{"post":{"operationId":"onboarding.completeOwner","description":"Also publishes the booking page once it meets the publish requirements.\nThe wizard's last screen tells the owner their page is live and hands\nthem the link; without this nothing ever published it, so that link was\na 404 until the owner found the publish toggle in settings on their own.\n`missing` lists what still blocks publishing (a gallery photo, usually).","summary":"Mark organization owner onboarding as complete.\nSets onboarding_completed_at on the organization so the setup wizard is not shown again","tags":["Onboarding"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"is_published":{"type":"boolean"},"missing":{"type":"array","items":{"type":"string"}}},"required":["message","is_published","missing"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/onboarding/state":{"post":{"operationId":"onboarding.updateState","description":"The wizard step lives in the database (not localStorage) so the owner\nresumes where they left off — Telegram Mini App webviews are killed\naggressively and client-side state alone resets the wizard to step 1.","summary":"Persist the owner's setup wizard progress","tags":["Onboarding"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOnboardingStateRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"onboarding_state":{"type":"object","properties":{"current_step":{"type":"integer"},"completed_steps":{"type":"array","items":{"type":"integer"}}},"required":["current_step","completed_steps"]}},"required":["message","onboarding_state"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/onboarding/staff-complete":{"post":{"operationId":"onboarding.completeStaff","summary":"Mark staff onboarding as complete for the currently authenticated staff member.\nSets onboarding_completed_at on the staff record so the welcome screen is not shown again","tags":["Onboarding"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff onboarding marked as complete."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/auth/organizations":{"get":{"operationId":"organization.index_0","tags":["Organization"],"responses":{"200":{"description":"Array of `OrganizationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/organizations":{"post":{"operationId":"organization.store","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationRequest"}}}},"responses":{"200":{"description":"`OrganizationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"get":{"operationId":"organizations.index","tags":["Organization"],"responses":{"200":{"description":"Array of `OrganizationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/organizations/{organization}":{"get":{"operationId":"organization.show","tags":["Organization"],"parameters":[{"name":"organization","in":"path","required":true,"description":"The organization ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`OrganizationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"An error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview.","example":"Unauthorized"}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"organizations.update","tags":["Organization"],"parameters":[{"name":"organization","in":"path","required":true,"description":"The organization ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationRequest"}}}},"responses":{"200":{"description":"`OrganizationResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"An error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview.","example":"Unauthorized"}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"organizations.destroy","tags":["Organization"],"parameters":[{"name":"organization","in":"path","required":true,"description":"The organization ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Unauthorized"]}},"required":["message"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/invite-code/generate":{"post":{"operationId":"organization.generateInviteCode","summary":"Generate invite code for an organization","tags":["Organization"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Invite code generated successfully."]},"invite_code":{"type":"string"}},"required":["message","invite_code"]},{"type":"object","properties":{"message":{"type":"string","enum":["Organization already has an invite code."]},"invite_code":{"type":"string"}},"required":["message","invite_code"]}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/invite-code/regenerate":{"post":{"operationId":"organization.regenerateInviteCode","summary":"Regenerate invite code for an organization","tags":["Organization"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invite code regenerated successfully."]},"invite_code":{"type":"string"}},"required":["message","invite_code"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/notification-settings/catalog":{"get":{"operationId":"organizationNotificationSetting.catalog","description":"Both settings screens render from this rather than from a hard-coded\nlist, so adding an event to the registry surfaces it in the UI without a\nfrontend change.","summary":"The catalogue of everything the provider bot can send","tags":["OrganizationNotificationSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"categories":{"type":"array","items":{"$ref":"#/components/schemas/NotificationCategoryResource"}},"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/NotificationDeliveryOptionResource"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/NotificationEventResource"}}},"required":["categories","deliveries","events"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/notification-settings":{"get":{"operationId":"organizationNotificationSetting.show","summary":"Get notification settings for the current organization.\nCreates with defaults if not found","tags":["OrganizationNotificationSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationNotificationSettingResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"organizationNotificationSetting.update","summary":"Update notification settings for the current organization","tags":["OrganizationNotificationSetting"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationSettingRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationNotificationSettingResource"},"message":{"type":"string","enum":["Notification settings updated."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/payment-settings":{"get":{"operationId":"organizationPaymentSetting.index","summary":"List all payment settings for the current organization","tags":["OrganizationPaymentSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationPaymentSettingResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"organizationPaymentSetting.upsert","summary":"Create or update a payment setting for a provider.\nUses upsert on (organization_id, provider) unique constraint","tags":["OrganizationPaymentSetting"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertPaymentSettingRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/payment-settings/{paymentSetting}":{"get":{"operationId":"organizationPaymentSetting.show","summary":"Get a specific payment setting","tags":["OrganizationPaymentSetting"],"parameters":[{"name":"paymentSetting","in":"path","required":true,"description":"The payment setting ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationPaymentSettingResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"delete":{"operationId":"organizationPaymentSetting.destroy","summary":"Delete a payment setting","tags":["OrganizationPaymentSetting"],"parameters":[{"name":"paymentSetting","in":"path","required":true,"description":"The payment setting ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Payment setting deleted."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/payment-settings/{paymentSetting}/toggle":{"post":{"operationId":"organizationPaymentSetting.toggle","summary":"Toggle the enabled state of a payment setting","tags":["OrganizationPaymentSetting"],"parameters":[{"name":"paymentSetting","in":"path","required":true,"description":"The payment setting ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationPaymentSettingResource"},"message":{"type":"string","enum":["Payment provider enabled.","Payment provider disabled."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/payment-settings/{paymentSetting}/validate":{"post":{"operationId":"organizationPaymentSetting.validateCredentials","summary":"Validate stored credentials by running a health check against the provider","tags":["OrganizationPaymentSetting"],"parameters":[{"name":"paymentSetting","in":"path","required":true,"description":"The payment setting ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"message":{"type":"string","enum":["Credentials are valid.","Invalid credentials."]}},"required":["valid","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"message":{"type":"string","enum":["No credentials configured."]}},"required":["valid","message"]}}}}}}},"/organization-profiles/search":{"get":{"operationId":"organizationProfile.search","summary":"Search/list public organization profiles (marketplace)\nPublic endpoint for marketplace/directory","tags":["OrganizationProfile"],"parameters":[{"name":"q","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"specialty","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"category","in":"query","schema":{"type":["string","null"],"maxLength":100}},{"name":"city","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"state","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"district","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"featured","in":"query","schema":{"type":["boolean","null"]}},{"name":"min_rating","in":"query","schema":{"type":["number","null"],"minimum":0,"maximum":5}},{"name":"price_min","in":"query","schema":{"type":["number","null"],"minimum":0}},{"name":"price_max","in":"query","schema":{"type":["number","null"],"minimum":0}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["relevance","recommended","daily","rating","reviews","name","created_at","price","distance"]}},{"name":"sort_direction","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}},{"name":"lat","in":"query","schema":{"type":["number","null"],"minimum":-90,"maximum":90}},{"name":"lng","in":"query","schema":{"type":["number","null"],"minimum":-180,"maximum":180}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"bounds_north","in":"query","description":"Bounding box for map viewport filtering (Leaflet can return values outside normal range when zoomed out)","schema":{"type":["number","null"]}},{"name":"bounds_south","in":"query","schema":{"type":["number","null"]}},{"name":"bounds_east","in":"query","schema":{"type":["number","null"]}},{"name":"bounds_west","in":"query","schema":{"type":["number","null"]}}],"responses":{"200":{"description":"Array of `OrganizationProfileResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}},"required":["data"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/organization-profiles/search/map":{"get":{"operationId":"organizationProfile.searchMapMarkers","summary":"Get lightweight map markers for all matching profiles (no pagination).\nPublic endpoint for marketplace map view","tags":["OrganizationProfile"],"parameters":[{"name":"q","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"specialty","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"category","in":"query","schema":{"type":["string","null"],"maxLength":100}},{"name":"city","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"state","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"district","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"featured","in":"query","schema":{"type":["boolean","null"]}},{"name":"min_rating","in":"query","schema":{"type":["number","null"],"minimum":0,"maximum":5}},{"name":"price_min","in":"query","schema":{"type":["number","null"],"minimum":0}},{"name":"price_max","in":"query","schema":{"type":["number","null"],"minimum":0}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["relevance","recommended","daily","rating","reviews","name","created_at","price","distance"]}},{"name":"sort_direction","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}},{"name":"lat","in":"query","schema":{"type":["number","null"],"minimum":-90,"maximum":90}},{"name":"lng","in":"query","schema":{"type":["number","null"],"minimum":-180,"maximum":180}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"bounds_north","in":"query","description":"Bounding box for map viewport filtering (Leaflet can return values outside normal range when zoomed out)","schema":{"type":["number","null"]}},{"name":"bounds_south","in":"query","schema":{"type":["number","null"]}},{"name":"bounds_east","in":"query","schema":{"type":["number","null"]}},{"name":"bounds_west","in":"query","schema":{"type":["number","null"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"markers":{"type":"string"},"total":{"type":"string"},"capped":{"type":"string"}},"required":["markers","total","capped"]},{"type":"object","properties":{"markers":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"total":{"type":"integer","enum":[0]},"capped":{"type":"boolean"}},"required":["markers","total","capped"]}]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/organization-profiles/autocomplete":{"get":{"operationId":"organizationProfile.autocomplete","description":"The panel loads more as it is scrolled, which it does by asking for a\nbigger slice of the same three groups rather than an offset — the groups\nare heterogeneous and each is ranked independently, so a shared cursor\nwould have nothing coherent to point at.","summary":"Autocomplete suggestions for marketplace search","tags":["OrganizationProfile"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":5}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"organizations":{"type":"string"},"categories":{"type":"string"},"cities":{"type":"string"}},"required":["organizations","categories","cities"]},{"type":"object","properties":{"organizations":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"categories":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"cities":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}},"required":["organizations","categories","cities"]}]}}}}}}},"/organization-profiles/filter-metadata":{"get":{"operationId":"organizationProfile.filterMetadata","summary":"Get available filter options for marketplace search sidebar","tags":["OrganizationProfile"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]},"count":{"type":"integer"}},"required":["slug","name","icon","illustration","count"]}},"price_range":{"type":"object","properties":{"min":{"type":"number"},"max":{"type":"number"}},"required":["min","max"]},"districts":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"]}},"specialties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"]}},"total_count":{"type":"integer"},"avg_rating":{"type":"number"},"monthly_bookings":{"type":"integer"},"total_reviews":{"type":"integer"},"rating_distribution":{"type":"array","items":{"type":"object","properties":{"rating":{"type":"integer"},"count":{"type":"integer"},"percentage":{"type":"number"}},"required":["rating","count","percentage"]}},"featured_review":{"type":["object","null"],"properties":{"rating":{"type":"integer"},"comment":{"type":"string"},"client_name":{"type":"string"},"city":{"type":["string","null"]}},"required":["rating","comment","client_name","city"]}},"required":["categories","price_range","districts","specialties","total_count","avg_rating","monthly_bookings","total_reviews","rating_distribution","featured_review"]}}}}}}},"/organization-profiles/{slug}":{"get":{"operationId":"organization-profiles.show","summary":"Get a single organization profile by slug (SEO page)\nPublic endpoint","tags":["OrganizationProfile"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"is_bookable":{"type":"boolean"},"organization":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":"string"},"slug":{"type":"string"},"specialty":{"type":["string","null"]},"description":{"type":["string","null"]},"logo":{"type":["string","null"]},"address":{"type":["string","null"]},"district":{"type":["string","null"]},"city":{"type":["string","null"]},"city_slug":{"type":["string","null"]},"canonical_path":{"type":"string"},"short_code":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"timezone":{"type":"string"},"default_currency":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]},"website":{"type":["string","null"]},"is_claimed":{"type":"boolean"},"is_active":{"type":"boolean"},"is_verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"created_at":{"type":["string","null"]},"updated_at":{"type":["string","null"]}},"required":["id","business_name","slug","specialty","description","logo","address","district","city","city_slug","canonical_path","short_code","state","country","postal_code","timezone","default_currency","phone","email","website","is_claimed","is_active","is_verified","verified_at","created_at","updated_at"]},"profile":{"$ref":"#/components/schemas/OrganizationProfileResource"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceResource"}},"featured_services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceResource"}},"staff":{"type":"array","items":{"$ref":"#/components/schemas/StaffResource"}},"featured_staff":{"type":"array","items":{"$ref":"#/components/schemas/StaffResource"}},"branches":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"masked_phone":{"type":["string","null"]},"is_main":{"type":"boolean"},"latitude":{"type":["string","null"]},"longitude":{"type":["string","null"]}},"required":["id","name","address","city","state","masked_phone","is_main","latitude","longitude"]}},"reviews":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"rating":{"type":"integer"},"comment":{"type":["string","null"]},"reply":{"type":["string","null"]},"client_name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","rating","comment","reply","client_name","created_at"]}},"review_stats":{"type":"object","properties":{"average_rating":{"type":"number"},"total_count":{"type":"integer"}},"required":["average_rating","total_count"]},"external_ratings":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"rating":{"type":["number","null"]},"review_count":{"type":["integer","null"]},"url":{"type":["string","null"]},"synced_at":{"type":["string","null"]}},"required":["provider","rating","review_count","url","synced_at"]}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]}},"required":["id","slug","name","icon"]}},"structured_data":{"type":"object","additionalProperties":{}},"seo":{"type":"object","properties":{"locale":{"type":"string"},"is_indexable":{"type":"boolean"},"robots":{"type":"string"},"failed":{"type":"array","items":{"type":"string"}},"criteria":{"type":"object","additionalProperties":{"type":"boolean"}}},"required":["locale","is_indexable","robots","failed","criteria"]},"demand":{"type":["object","null"],"properties":{"views_30d":{"type":"integer"},"phone_reveals_30d":{"type":"integer"},"since":{"type":"string"}},"required":["views_30d","phone_reveals_30d","since"]}},"required":["is_bookable","organization","profile","services","featured_services","staff","featured_staff","branches","reviews","review_stats","external_ratings","categories","structured_data","seo","demand"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/organization-profiles/{slug}/slots":{"get":{"operationId":"organizationProfile.slots","tags":["OrganizationProfile"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"staff_id","in":"query","schema":{"type":["integer","null"]}},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string"},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"duration":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"slots":{"type":"array","items":{"$ref":"#/components/schemas/SlotResource"}}},"required":["date","service","staff","slots"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/organization-profiles/{slug}/nearby":{"get":{"operationId":"organizationProfile.nearby","summary":"Get nearby venues in the same city as the given organization.\nPublic endpoint","tags":["OrganizationProfile"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"venues":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"business_name":{"type":"string"},"specialty":{"type":["string","null"]},"city":{"type":["string","null"]},"city_slug":{"type":["string","null"]},"primary_category":{"type":["object","null"],"properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"}},"required":["slug","locale_slug"]},"cover_image":{"type":["string","null"]},"map_photo":{"type":["string","null"]},"logo":{"type":["string","null"]},"average_rating":{"type":"number"},"total_reviews":{"type":"integer"},"accent_color":{"type":["string","null"]}},"required":["id","slug","business_name","specialty","city","city_slug","primary_category","cover_image","map_photo","logo","average_rating","total_reviews","accent_color"]}}},"required":["venues"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/organization-profiles/{slug}/phone":{"get":{"operationId":"organizationProfile.revealPhone","description":"Also returns the messenger links whose handle is a phone number\n(`t.me/+998…`, `wa.me/998…`). Those are stripped from the public profile\nfor the same reason the number itself is masked there, so this is the\nonly place they come back — a caller that wants to open Telegram has to\npass the same throttle as one that wants to dial.","summary":"Reveal full phone number for an organization profile.\nRate-limited public endpoint to prevent scraping","tags":["OrganizationProfile"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"intent","in":"query","description":"Why the visitor asked. The same reveal returns the messenger\nlinks, and a \"Write on Telegram\" tap must not be counted as\nsomeone pressing Call. Omitted means `call`.","schema":{"type":"string","enum":["call","messenger"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":["string","null"]},"contacts":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"url":{"type":"string"},"phone":{"type":"string"}},"required":["platform","url","phone"]}}},"required":["phone","contacts"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/organization-profiles/{slug}/events":{"post":{"operationId":"organizationProfile.recordEvent","description":"A fire-and-forget beacon from the venue page, feeding the demand counters\nan unclaimed venue's owner is shown (\"N people opened your page\"). Bots\nand repeats from the same visitor on the same day are dropped silently, so\nthe answer is always 204 — the caller has nothing to do either way. Phone\nreveals are not accepted here; the reveal endpoint counts its own.\n\nPublic endpoint, published profiles only.","summary":"Count a visitor's interest in a venue: a page open, a messenger tap or a\ndirections tap","tags":["OrganizationProfile"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordVenueEventRequest"}}}},"responses":{"204":{"description":"No content"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/organization-profile":{"get":{"operationId":"organizationProfile.getOrCreateProfile","summary":"Get or create profile for authenticated organization owner\nProtected endpoint (staff only)","tags":["OrganizationProfile"],"responses":{"200":{"description":"`OrganizationProfileResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationProfileResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"organizationProfile.update","summary":"Update organization profile\nProtected endpoint (staff only)","tags":["OrganizationProfile"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationProfileRequest"}}}},"responses":{"200":{"description":"`OrganizationProfileResource`","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationProfileResource"}},"required":["data"]},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/organization-profile/toggle-publish":{"post":{"operationId":"organizationProfile.togglePublish","summary":"Publish/unpublish profile\nProtected endpoint (staff only)","tags":["OrganizationProfile"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Profile unpublished"]},"profile":{"$ref":"#/components/schemas/OrganizationProfileResource"}},"required":["message","profile"]},{"type":"object","properties":{"message":{"type":"string","enum":["Profile published"]},"profile":{"$ref":"#/components/schemas/OrganizationProfileResource"}},"required":["message","profile"]}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Profile not found"]}},"required":["message"]}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"object","properties":{"requirements":{"type":"string"}},"required":["requirements"]}},"required":["message","errors"]}}}}}}},"/org/organization-profile/update-stats":{"post":{"operationId":"organizationProfile.updateStats","summary":"Update profile stats manually\nProtected endpoint (staff only)","tags":["OrganizationProfile"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Stats updated successfully"]},"profile":{"$ref":"#/components/schemas/OrganizationProfileResource"}},"required":["message","profile"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Profile not found"]}},"required":["message"]}}}}}}},"/partner/validate-code":{"post":{"operationId":"partnerReferral.validateCode","description":"Public check used on the business signup page to confirm a partner code\nand show a friendly \"invited by\" badge.","summary":"POST /api/partner/validate-code","tags":["PartnerReferral"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidatePartnerCodeRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"valid":{"type":"boolean"},"name":{"type":["string","null"]}},"required":["valid","name"]},{"type":"object","properties":{"valid":{"type":"boolean"},"name":{"type":"null"}},"required":["valid","name"]}]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/payment/payme/callback":{"post":{"operationId":"paymeCallback.handle","tags":["PaymeCallback"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string"},"id":{"type":"string"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"result":{"type":"null"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"object","properties":{"uz":{"type":"string","enum":["Internal server error"]},"ru":{"type":"string","enum":["Internal server error"]},"en":{"type":"string","enum":["Internal server error"]}},"required":["uz","ru","en"]}},"required":["code","message"]}},"required":["id","result","error"]},{"type":"string"}]}}}}}}},"/org/payments/appointments/{appointment}":{"get":{"operationId":"payment.index","summary":"List payment transactions for an appointment","tags":["Payment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentTransactionResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/payments/appointments/{appointment}/initiate":{"post":{"operationId":"payment.initiate","summary":"Initiate a payment for an appointment","tags":["Payment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiatePaymentRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentTransactionResource"},"checkout":{"type":"string"}},"required":["data","checkout"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/payments/appointments/{appointment}/requirement":{"get":{"operationId":"payment.requirement","summary":"Get payment requirement for an appointment","tags":["Payment"],"parameters":[{"name":"appointment","in":"path","required":true,"description":"The appointment ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"integer"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"anyOf":[{"type":"integer"},{"type":"integer","enum":[100]}]},"providers":{"type":"string"},"refund_on_cancellation":{"type":"string"},"refund_deadline_hours":{"type":"string"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]},{"type":"object","properties":{"required":{"type":"boolean"},"policy":{"type":"string"},"amount":{"type":"null"},"currency":{"type":"string"},"currency_scale":{"type":"integer"},"percentage":{"type":"integer","enum":[0]},"providers":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"refund_on_cancellation":{"type":"boolean"},"refund_deadline_hours":{"type":"null"}},"required":["required","policy","amount","currency","currency_scale","percentage","providers","refund_on_cancellation","refund_deadline_hours"]}]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/payments/{transaction}":{"get":{"operationId":"payment.status","summary":"Get the status of a specific payment transaction","tags":["Payment"],"parameters":[{"name":"transaction","in":"path","required":true,"description":"The transaction ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentTransactionResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/payments/{transaction}/refund":{"post":{"operationId":"payment.refund","summary":"Request a refund for a payment transaction","tags":["Payment"],"parameters":[{"name":"transaction","in":"path","required":true,"description":"The transaction ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentTransactionResource"},"provider_response":{"type":"array","items":{}}},"required":["data","provider_response"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/platform/sales-contact":{"get":{"operationId":"platformContact.salesContact","description":"`sales_bot_username` is the sales bot's Telegram username without the `@`,\nor null while there is none, in which case the frontend falls back to its\nsupport link.","summary":"Who to send a business to for a conversation with a manager","tags":["PlatformContact"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"sales_bot_username":{"type":["string","null"]}},"required":["sales_bot_username"]}}}}}}},"/referrals/validate-code":{"post":{"operationId":"referral.validateCode","summary":"Validate a referral code (public endpoint for the onboarding form)","tags":["Referral"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","maxLength":10}},"required":["code"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"data":{"type":"object","properties":{"business_name":{"type":"string"},"slug":{"type":"string"},"logo":{"type":"string"}},"required":["business_name","slug","logo"]}},"required":["data"]},{"type":"object","properties":{"data":{"type":"null"}},"required":["data"]}]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/referrals":{"get":{"operationId":"referral.index","summary":"List referrals made by the current organization (as referrer)","tags":["Referral"],"responses":{"200":{"description":"Paginated set of `ReferralResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReferralResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/referrals/stats":{"get":{"operationId":"referral.stats","summary":"Get referral statistics for the current organization","tags":["Referral"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"total":{"type":"string"},"pending":{"type":"string"},"completed":{"type":"string"},"total_days_earned":{"type":"string"},"referral_code":{"type":"string"},"referral_link":{"type":"string"},"reward_days":{"type":"string"}},"required":["total","pending","completed","total_days_earned","referral_code","referral_link","reward_days"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/referrals/incoming":{"get":{"operationId":"referral.incoming","summary":"Get the incoming referral (where the current org was referred)","tags":["Referral"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/ReferralResource"},{"type":"null"}]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/referrals/regenerate-code":{"post":{"operationId":"referral.regenerateCode","summary":"Regenerate the referral code for the current organization","tags":["Referral"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"referral_code":{"type":"string"},"referral_link":{"type":"string"}},"required":["referral_code","referral_link"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/reviews":{"get":{"operationId":"review.index","summary":"List reviews for the organization with filtering and sorting","tags":["Review"],"parameters":[{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"rating","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":5}},{"name":"is_public","in":"query","schema":{"type":["boolean","null"]}},{"name":"has_reply","in":"query","schema":{"type":["boolean","null"]}},{"name":"is_reported","in":"query","schema":{"type":["boolean","null"]}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["created_at","rating"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Paginated set of `ReviewResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/reviews/stats":{"get":{"operationId":"review.stats","summary":"Get review statistics for the organization","tags":["Review"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"total_count":{"type":"integer"},"average_rating":{"type":"number"},"distribution":{"type":"array","prefixItems":[{"type":"integer"},{"type":"integer"},{"type":"integer"},{"type":"integer"},{"type":"integer"}],"minItems":5,"maxItems":5,"additionalItems":false},"replied_count":{"type":"integer"},"unreplied_count":{"type":"integer"},"public_count":{"type":"integer"},"private_count":{"type":"integer"},"reported_count":{"type":"integer"}},"required":["total_count","average_rating","distribution","replied_count","unreplied_count","public_count","private_count","reported_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/reviews/trend":{"get":{"operationId":"review.trend","summary":"Get review trend data for the organization","tags":["Review"],"parameters":[{"name":"range","in":"query","required":true,"schema":{"type":"string","enum":["30d","3m","6m","12m"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","prefixItems":[{"type":"object","properties":{"date":{"type":"string"},"reviews":{"type":"integer"}},"required":["date","reviews"]}],"minItems":1,"maxItems":1,"additionalItems":false}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/reviews/{review}":{"get":{"operationId":"review.show","summary":"Get a single review","tags":["Review"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ReviewResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReviewResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"review.update","summary":"Update review moderation (visibility)","tags":["Review"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviewModerationRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Review updated successfully"]},"review":{"$ref":"#/components/schemas/ReviewResource"}},"required":["message","review"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/reviews/{review}/reply":{"post":{"operationId":"review.reply","summary":"Reply to a review","tags":["Review"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyReviewRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Reply added successfully"]},"review":{"$ref":"#/components/schemas/ReviewResource"}},"required":["message","review"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/reviews/{review}/report":{"post":{"operationId":"review.report","summary":"Report a review","tags":["Review"],"parameters":[{"name":"review","in":"path","required":true,"description":"The review ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportReviewRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Review reported successfully"]},"review":{"$ref":"#/components/schemas/ReviewResource"}},"required":["message","review"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/search":{"get":{"operationId":"search","summary":"Universal search across all entity types","tags":["Search"],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"maxLength":100}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"results":{"type":"object","properties":{"staff":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false},"branches":{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}},"required":["staff","branches"]},"counts":{"type":"object","properties":{"staff":{"type":"integer","enum":[0]},"branches":{"type":"integer","enum":[0]}},"required":["staff","branches"]}},"required":["query","results","counts"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/seo/sitemap-index":{"get":{"operationId":"seo.sitemap-index","summary":"Sitemap index: every locale sitemap file and how many URLs it holds","tags":["SeoSitemap"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"urls_per_file":{"type":"integer"},"total":{"type":"integer"},"sitemaps":{"type":"array","items":{"type":"object","properties":{"locale":{"type":"string"},"page":{"type":"integer"},"count":{"type":"integer"},"lastmod":{"type":["string","null"]}},"required":["locale","page","count","lastmod"]}}},"required":["urls_per_file","total","sitemaps"]}}}}}}},"/seo/sitemap-urls":{"get":{"operationId":"seo.sitemap-urls","description":"`total` is what the gate matched, `count` is what this response actually\ncontains. They must agree for a full page; a consumer that sees them\ndiverge should treat the feed as broken rather than publish a plausible\nbut truncated sitemap — that exact failure once shipped 8 of ~19k URLs at\nHTTP 200.","summary":"One sitemap page of indexable venue URLs for a locale","tags":["SeoSitemap"],"parameters":[{"name":"locale","in":"query","schema":{"type":"string","enum":["ru","uz","en"]}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"locale":{"type":"string"},"page":{"type":"integer"},"last_page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"count":{"type":"integer"},"urls":{"type":"array","items":{"$ref":"#/components/schemas/SitemapUrlResource"}}},"required":["locale","page","last_page","per_page","total","count","urls"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/services/categories":{"get":{"operationId":"service.categories","summary":"Get categories for services","tags":["Service"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/services":{"get":{"operationId":"services.index","tags":["Service"],"parameters":[{"name":"category_id","in":"query","schema":{"type":["integer","null"]}},{"name":"active","in":"query","schema":{"type":["boolean","null"]}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["id","name","duration","price","created_at"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated set of `ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ServiceResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"post":{"operationId":"services.store","tags":["Service"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequest"}}}},"responses":{"200":{"description":"`ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ServiceResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/services/{service}":{"get":{"operationId":"services.show","tags":["Service"],"parameters":[{"name":"service","in":"path","required":true,"description":"The service ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ServiceResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"services.update","tags":["Service"],"parameters":[{"name":"service","in":"path","required":true,"description":"The service ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceRequest"}}}},"responses":{"200":{"description":"`ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ServiceResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"services.destroy","tags":["Service"],"parameters":[{"name":"service","in":"path","required":true,"description":"The service ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Service deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/services/{service}/staff":{"get":{"operationId":"service.staff","summary":"Get staff that can perform this service","tags":["Service"],"parameters":[{"name":"service","in":"path","required":true,"description":"The service ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Staff"}}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"post":{"operationId":"service.assignStaff","summary":"Assign staff to service","tags":["Service"],"parameters":[{"name":"service","in":"path","required":true,"description":"The service ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignStaffToServiceRequest"}}}},"responses":{"200":{"description":"`ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ServiceResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/services/batch-update":{"post":{"operationId":"service.batchUpdate","summary":"Batch update services","tags":["Service"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateServicesRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"updated_count":{"type":"string"}},"required":["message","updated_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/services/batch-destroy":{"post":{"operationId":"service.batchDestroy","summary":"Batch delete services","tags":["Service"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDestroyServicesRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"deleted_count":{"type":"string"}},"required":["message","deleted_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/settings":{"get":{"operationId":"settings.index","tags":["Settings"],"responses":{"200":{"description":"`SettingsResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SettingsResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"settings.update","tags":["Settings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationSettingsRequest"}}}},"responses":{"200":{"description":"`SettingsResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SettingsResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/setup-status":{"get":{"operationId":"setupStatus","description":"Returns requirements, suggestions, score, and bookable/publishable flags.","summary":"Get the organization's completeness status","tags":["SetupStatus"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"score":{"type":"integer"},"is_bookable":{"type":"string"},"is_publishable":{"type":"boolean"},"requirements":{"type":"object","properties":{"has_working_hours":{"type":"string"},"has_service":{"type":"string"},"has_staff":{"type":"string"},"has_photo":{"type":"string"}},"required":["has_working_hours","has_service","has_staff","has_photo"]},"suggestions":{"type":"array","prefixItems":[{"type":"object","properties":{"key":{"type":"string","enum":["add_logo"]},"weight":{"type":"integer","enum":[10]},"label":{"type":"string","enum":["Add a logo to your organization"]},"completed":{"type":"boolean"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_cover_image"]},"weight":{"type":"integer","enum":[10]},"label":{"type":"string","enum":["Add a cover image to your profile"]},"completed":{"type":"boolean"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_more_photos"]},"weight":{"type":"integer","enum":[10]},"label":{"type":"string","enum":["Add at least 3 photos to your gallery"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_about"]},"weight":{"type":"integer","enum":[10]},"label":{"type":"string","enum":["Write an about section for your profile"]},"completed":{"type":"boolean"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_contact"]},"weight":{"type":"integer","enum":[5]},"label":{"type":"string","enum":["Add a phone number or email to your profile"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_social_links"]},"weight":{"type":"integer","enum":[5]},"label":{"type":"string","enum":["Add at least one social link"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_business_hours"]},"weight":{"type":"integer","enum":[5]},"label":{"type":"string","enum":["Add business hours to your profile"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["add_faq"]},"weight":{"type":"integer","enum":[5]},"label":{"type":"string","enum":["Add at least one FAQ item"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]},{"type":"object","properties":{"key":{"type":"string","enum":["staff_avatars"]},"weight":{"type":"integer","enum":[5]},"label":{"type":"string","enum":["Ensure all active staff have profile photos"]},"completed":{"type":"string"}},"required":["key","weight","label","completed"]}],"minItems":9,"maxItems":9,"additionalItems":false},"booking_url":{"type":"string","description":"The venue's real address (ODI-182). The flat `/{slug}` this used\nto build 404s, and this value is shown to the owner as \"your page\"."},"onboarding_completed":{"type":"boolean"},"staff_count":{"type":"string"},"is_solo":{"type":"boolean"},"referral_count":{"type":"string"}},"required":["score","is_bookable","is_publishable","requirements","suggestions","booking_url","onboarding_completed","staff_count","is_solo","referral_count"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/short-links/{code}":{"get":{"operationId":"short-links.show","tags":["ShortLink"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"The venue's locale-less canonical path: `/tashkent/barber/britva`."}},"required":["path"]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Not found"]}},"required":["message"]}}}}}}},"/org/staff":{"get":{"operationId":"staff.index","tags":["Staff"],"parameters":[{"name":"active","in":"query","schema":{"type":["boolean","null"]}},{"name":"branch_id","in":"query","schema":{"type":["integer","null"]}},{"name":"role","in":"query","schema":{"type":["string","null"],"enum":["owner","manager","service_provider","receptionist"]}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["id","name","email","created_at"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated set of `StaffResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"post":{"operationId":"staff.store","tags":["Staff"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateStaffRequest"}}}},"responses":{"200":{"description":"`StaffResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"upgrade_required":{"type":"boolean"}},"required":["message","upgrade_required"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/staff/{staff}":{"get":{"operationId":"staff.show","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`StaffResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"staff.update","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStaffRequest"}}}},"responses":{"200":{"description":"`StaffResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}},"delete":{"operationId":"staff.destroy","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff member deleted"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/staff/{staff}/availability":{"get":{"operationId":"staff.availability","summary":"Get availability for a staff member","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"put":{"operationId":"staff.updateAvailability","summary":"Update availability for a staff member","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStaffAvailabilityRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/staff/{staff}/services":{"get":{"operationId":"staff.services","summary":"Get services assigned to this staff member","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"Array of `ServiceResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ServiceResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"post":{"operationId":"staff.assignServices","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStaffServicesRequest"}}}},"responses":{"200":{"description":"`StaffResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/staff/batch-update":{"post":{"operationId":"staff.batchUpdate","summary":"Batch update staff members","tags":["Staff"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateStaffRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"updated_count":{"type":"string"}},"required":["message","updated_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/staff/batch-destroy":{"post":{"operationId":"staff.batchDestroy","summary":"Batch delete staff members","tags":["Staff"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDestroyStaffRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"deleted_count":{"type":"string"}},"required":["message","deleted_count"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/staff/{staff}/deactivate":{"post":{"operationId":"staff.deactivate","summary":"Deactivate a staff member","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff member deactivated"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/staff/{staff}/activate":{"post":{"operationId":"staff.activate","summary":"Activate a staff member","tags":["Staff"],"parameters":[{"name":"staff","in":"path","required":true,"description":"The staff ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Staff member activated"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/auth/login":{"post":{"operationId":"staffAuth.login","summary":"Login:\n- If auth_method=password -> verify password -> return token.\n- If auth_method=code -> generate code -> return \"code sent\"","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgLoginRequest"}}}},"responses":{"200":{"description":"Load orgs to check if the profile is filled","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Verification code sent."]},"action":{"type":"string","enum":["verify_code"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"anyOf":[{"type":"string"},{"type":"string","enum":["654321"]}]}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message","action",null]},{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"user":{"type":"string"},"action":{"type":"string","enum":["login_success"]}},"required":["access_token","token_type","user","action"]}]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["User not found."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/auth/register":{"post":{"operationId":"staffAuth.register","summary":"Register:\n- Creates user.\n- If auth_method=password -> sets password.\n- ALWAYS sends code for verification (even if password set)","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRegisterRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Registration successful. Please verify your account."]},"action":{"type":"string","enum":["verify_code"]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"anyOf":[{"type":"string"},{"type":"string","enum":["654321"]}]}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message","action",null]}}}},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/auth/verify":{"post":{"operationId":"staffAuth.verify","summary":"Verify Code:\n- Verifies code.\n- Marks email/phone verified.\n- Returns token","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgVerifyRequest"}}}},"responses":{"200":{"description":"Load orgs to check if the profile is filled","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"user":{"type":"string"},"action":{"type":"string","enum":["login_success"]}},"required":["access_token","token_type","user","action"]}}}},"404":{"description":"No `debug_info` here. It used to echo the identifier, the column\nand the literal query back in every environment, which handed an\nattacker both an account-existence oracle and a description of\nthe lookup.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["User not found."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/auth/resend":{"post":{"operationId":"staffAuth.resend","summary":"Resend Code","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResendRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Verification code resent."]},"":{"anyOf":[{"type":"object","properties":{"debug_code":{"anyOf":[{"type":"string"},{"type":"string","enum":["654321"]}]}},"required":["debug_code"]},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]}},"required":["message",null]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["User not found."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/auth/invite":{"post":{"operationId":"staffAuth.invite","description":"Reuses an existing Bronjoy account with that email (a stylist who once\nbooked as a client, or works at another salon) and only creates a user\nwhen none exists. The invitee signs in through the normal provider-app\nemail + one-time-code flow, so the invitation email carries no code.","summary":"Invite a staff member (Owner only)","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffInviteRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/profile/update":{"post":{"operationId":"staffAuth.updateProfile","summary":"Update Profile (Create Organization)","tags":["StaffAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgProfileUpdateRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Profile updated successfully."]},"organization":{"type":"string"},"user":{"type":"string"}},"required":["message","organization","user"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/my-notification-preferences":{"get":{"operationId":"staffNotificationPreference.show","tags":["StaffNotificationPreference"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffNotificationPreferenceResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["You are not a member of this organization"]}},"required":["message"]}}}}}},"put":{"operationId":"staffNotificationPreference.update","tags":["StaffNotificationPreference"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStaffNotificationPreferenceRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffNotificationPreferenceResource"},"message":{"type":"string","enum":["Notification preferences updated."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["You are not a member of this organization"]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/my-notification-preferences/snooze":{"post":{"operationId":"staffNotificationPreference.snooze","summary":"Silence everything except critical events for a while. Sending no\nminutes clears the snooze","tags":["StaffNotificationPreference"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"minutes":{"type":"integer","minimum":0,"maximum":10080}},"required":["minutes"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffNotificationPreferenceResource"},"message":{"type":"string","enum":["Notifications snoozed.","Snooze cleared."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["You are not a member of this organization"]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/my-notification-preferences/reconnect":{"post":{"operationId":"staffNotificationPreference.reconnect","summary":"Clear the \"this chat is unreachable\" flag after re-linking Telegram","tags":["StaffNotificationPreference"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffNotificationPreferenceResource"},"message":{"type":"string","enum":["Telegram delivery re-enabled."]}},"required":["data","message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["You are not a member of this organization"]}},"required":["message"]}}}}}}},"/organization-profiles/{orgSlug}/staff/{staffSlug}":{"get":{"operationId":"staff-profiles.show","summary":"Get a staff member's public profile page.\nPublic endpoint - no auth required","tags":["StaffProfile"],"parameters":[{"name":"orgSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"staffSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":"string"},"slug":{"type":"string"},"logo":{"type":["string","null"]},"specialty":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"address":{"type":["string","null"]},"timezone":{"type":"string"}},"required":["id","business_name","slug","logo","specialty","city","state","address","timezone"]},"profile":{"type":"object","properties":{"accent_color":{"type":["string","null"]}},"required":["accent_color"]},"staff":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"display_name":{"type":["string","null"]},"slug":{"type":"string"},"position":{"type":["string","null"]},"bio":{"type":["string","null"]},"avatar":{"type":["string","null"]},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]},"branch":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"address":{"type":["string","null"]}},"required":["id","name","address"]}},"required":["id","name","display_name","slug","position","bio","avatar","meta_title","meta_description","branch"]},"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":["string","null"]},"duration":{"type":"integer"},"price":{"type":"number"},"currency":{"type":"string"}},"required":["id","name","description","duration","price","currency"]}},"weekly_schedule":{"type":"array","items":{"type":"array","items":{"type":"object","properties":{"start_time":{"type":"string"},"end_time":{"type":"string"}},"required":["start_time","end_time"]}}},"structured_data":{"type":"object","additionalProperties":{}}},"required":["organization","profile","staff","services","weekly_schedule","structured_data"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/subscription/stripe/webhook":{"post":{"operationId":"stripeSubscriptionWebhook.handle","description":"Handle Stripe webhook events for subscription billing.\nPublic endpoint — no auth, validated by Stripe signature.","summary":"POST /api/subscription/stripe/webhook","tags":["StripeSubscriptionWebhook"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/payment/stripe/webhook":{"post":{"operationId":"stripeWebhook.handle","tags":["StripeWebhook"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["Internal server error"]}},"required":["error"]}}}}}}},"/org/subscription":{"get":{"operationId":"subscription.show","description":"Get the current subscription details + plan info + usage stats.","summary":"GET /api/org/subscription","tags":["Subscription"],"responses":{"200":{"description":"`SubscriptionResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SubscriptionResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/subscription/checkout":{"post":{"operationId":"subscription.checkout","description":"Create a Stripe checkout session for upgrading to Avtopilot.\nOwner only.","summary":"POST /api/org/subscription/checkout","tags":["Subscription"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSubscriptionRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"$ref":"#/components/responses/AuthorizationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/subscription/cancel":{"post":{"operationId":"subscription.cancel","description":"Cancel subscription at end of billing period. Owner only.","summary":"POST /api/org/subscription/cancel","tags":["Subscription"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Subscription will be cancelled at the end of the billing period."]}},"required":["message"]},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Subscription is already cancelled."]}},"required":["message"]},{"type":"object","properties":{"message":{"type":"string","enum":["Cannot cancel a free plan."]}},"required":["message"]}]}}}}}}},"/org/subscription/resume":{"post":{"operationId":"subscription.resume","description":"Resume a cancelled subscription. Owner only.","summary":"POST /api/org/subscription/resume","tags":["Subscription"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Subscription resumed."]}},"required":["message"]},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Subscription is not in a cancellable grace period."]}},"required":["message"]}}}}}}},"/org/subscription/branches/add":{"post":{"operationId":"subscription.addBranch","description":"Add an extra branch slot. Owner only.","summary":"POST /api/org/subscription/branches/add","tags":["Subscription"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Branch slot added."]}},"required":["message"]},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Branch add-ons require a paid plan."]},"upgrade_required":{"type":"boolean"}},"required":["message","upgrade_required"]}}}}}}},"/org/subscription/branches/remove":{"post":{"operationId":"subscription.removeBranch","description":"Remove an extra branch slot. Owner only.","summary":"POST /api/org/subscription/branches/remove","tags":["Subscription"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"message":{"type":"string","enum":["Branch slot removed."]}},"required":["message"]},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["No extra branches to remove."]}},"required":["message"]}}}}}}},"/org/subscription/ai-credits/topup":{"post":{"operationId":"subscription.topupAiCredits","description":"Start a one-time checkout to buy AI credit packs. Owner only.","summary":"POST /api/org/subscription/ai-credits/topup","tags":["Subscription"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"packs":{"type":["integer","null"],"minimum":1,"maximum":100}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"object"}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["AI credit top-ups require a paid plan."]},"upgrade_required":{"type":"boolean"}},"required":["message","upgrade_required"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/support/tickets":{"get":{"operationId":"org.support.index","summary":"List the organization's support tickets","tags":["SupportTicket"],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"per_page","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Paginated set of `SupportTicketResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicketResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"org.support.store","summary":"Open a new support ticket","tags":["SupportTicket"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreSupportTicketRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupportTicketResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/support/tickets/meta":{"get":{"operationId":"org.support.meta","summary":"Form metadata: available categories and priorities","tags":["SupportTicket"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"categories":{"type":"string"},"priorities":{"type":"string"}},"required":["categories","priorities"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/support/tickets/unread-count":{"get":{"operationId":"org.support.unreadCount","summary":"Total number of unread support replies across all of the org's tickets","tags":["SupportTicket"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"unread_count":{"type":"string"}},"required":["unread_count"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/support/tickets/{ticket}":{"get":{"operationId":"org.support.show","summary":"Show a single ticket with its full message thread","tags":["SupportTicket"],"parameters":[{"name":"ticket","in":"path","required":true,"description":"The ticket ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`SupportTicketResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupportTicketResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/support/tickets/{ticket}/messages":{"get":{"operationId":"org.support.messages","summary":"List messages for a ticket (used for chat polling)","tags":["SupportTicket"],"parameters":[{"name":"ticket","in":"path","required":true,"description":"The ticket ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"Array of `SupportTicketMessageResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicketMessageResource"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}},"post":{"operationId":"org.support.sendMessage","summary":"Post a new message to a ticket from the provider","tags":["SupportTicket"],"parameters":[{"name":"ticket","in":"path","required":true,"description":"The ticket ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreSupportTicketMessageRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupportTicketMessageResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/support/tickets/{ticket}/close":{"post":{"operationId":"org.support.close","summary":"Close (resolve) a ticket from the provider side","tags":["SupportTicket"],"parameters":[{"name":"ticket","in":"path","required":true,"description":"The ticket ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`SupportTicketResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupportTicketResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/support/tickets/{ticket}/reopen":{"post":{"operationId":"org.support.reopen","summary":"Re-open a previously resolved/closed ticket","tags":["SupportTicket"],"parameters":[{"name":"ticket","in":"path","required":true,"description":"The ticket ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`SupportTicketResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupportTicketResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/auth/telegram":{"post":{"operationId":"telegramAuth.staffAuth","description":"Route: POST /api/org/auth/telegram","summary":"Authenticate staff via Telegram Mini App initData.\nIf user doesn't exist, creates one and returns needs_onboarding flag.\nIf user has no organizations, returns needs_onboarding flag","tags":["TelegramAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramAuthRequest"}}}},"responses":{"200":{"description":"`TelegramStaffAuthResource`","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TelegramStaffAuthResource"}},"required":["data"]},{"type":"object"}]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/telegram/link":{"post":{"operationId":"telegramAuth.linkTelegram","description":"Route: POST /api/org/telegram/link","summary":"Link Telegram account to existing user.\nUsed when staff wants to connect their Telegram for notifications","tags":["TelegramAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramAuthRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Telegram account linked successfully"]},"telegram":{"type":"object","properties":{"user_id":{"type":"string"},"username":{"type":"string"}},"required":["user_id","username"]}},"required":["message","telegram"]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Invalid Telegram user data"]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["This Telegram account is already linked to another user."]}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/telegram/unlink":{"post":{"operationId":"telegramAuth.unlinkTelegram","description":"Route: POST /api/org/telegram/unlink","summary":"Unlink Telegram account from user","tags":["TelegramAuth"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Telegram account unlinked successfully"]}},"required":["message"]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["No Telegram account linked."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/telegram/create-organization":{"post":{"operationId":"telegramAuth.createOrganizationViaTelegram","description":"Route: POST /api/org/telegram/create-organization","summary":"Create a new organization via Telegram Mini App.\nUser must be authenticated via TMA","tags":["TelegramAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"business_name":{"type":"string","maxLength":255}},"required":["business_name"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Organization created successfully"]},"data":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["array","null"],"items":{}},"slug":{"type":"string"},"role":{"type":"array","prefixItems":[{"type":"string","enum":["owner"]}],"minItems":1,"maxItems":1,"additionalItems":false}},"required":["id","name","slug","role"]}},"required":["message","data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/telegram/join-organization":{"post":{"operationId":"telegramAuth.joinOrganizationViaTelegram","description":"Route: POST /api/org/telegram/join-organization","summary":"Join an existing organization via invite code in Telegram Mini App","tags":["TelegramAuth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":4,"maxLength":20}},"required":["code"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Successfully joined organization"]},"data":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["array","null"],"items":{}},"slug":{"type":"string"},"role":{"type":"array","prefixItems":[{"type":"string","enum":["service_provider"]}],"minItems":1,"maxItems":1,"additionalItems":false}},"required":["id","name","slug","role"]}},"required":["message","data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"403":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/telegram-bot":{"get":{"operationId":"telegramBot.status","description":"GET /api/org/telegram-bot","summary":"Get custom bot connection status","tags":["TelegramBot"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"data":{"type":"object","properties":{"connected":{"type":"boolean"},"bot_username":{"type":"string"},"bot_link":{"type":["string","null"]},"webhook":{"type":["object","null"],"properties":{"url":{"type":"string"},"pending_update_count":{"type":"string"},"last_error_message":{"type":"string"}},"required":["url","pending_update_count","last_error_message"]}},"required":["connected","bot_username","bot_link","webhook"]}},"required":["data"]},{"type":"object","properties":{"data":{"type":"object","properties":{"connected":{"type":"boolean"},"bot_username":{"type":"null"},"bot_link":{"type":"null"}},"required":["connected","bot_username","bot_link"]}},"required":["data"]}]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/telegram-bot/connect":{"post":{"operationId":"telegramBot.connect","description":"POST /api/org/telegram-bot/connect","summary":"Connect a custom Telegram bot","tags":["TelegramBot"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectTelegramBotRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Bot connected successfully"]},"data":{"type":"object","properties":{"connected":{"type":"boolean"},"bot_username":{"type":"string"},"bot_link":{"type":"string"}},"required":["connected","bot_username","bot_link"]}},"required":["message","data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Failed to set up webhook. Please try again."]}},"required":["message"]}}}}}}},"/org/telegram-bot/disconnect":{"post":{"operationId":"telegramBot.disconnect","description":"POST /api/org/telegram-bot/disconnect","summary":"Disconnect the custom Telegram bot","tags":["TelegramBot"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["Bot disconnected successfully"]},"data":{"type":"object","properties":{"connected":{"type":"boolean"},"bot_username":{"type":"null"},"bot_link":{"type":"null"}},"required":["connected","bot_username","bot_link"]}},"required":["message","data"]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","enum":["No custom bot is connected."]}},"required":["message"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/telegram/webhook/client":{"post":{"operationId":"telegramWebhook.clientWebhook","description":"Route: POST /api/telegram/webhook/client","summary":"Handle client bot webhook","tags":["TelegramWebhook"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},{"type":"null"},{"type":"object"}]}}}}}}},"/telegram/webhook/staff":{"post":{"operationId":"telegramWebhook.staffWebhook","description":"Route: POST /api/telegram/webhook/staff","summary":"Handle staff bot webhook","tags":["TelegramWebhook"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},{"type":"null"},{"type":"object"}]}}}}}}},"/telegram/webhook/support":{"post":{"operationId":"telegramWebhook.supportWebhook","description":"Every incoming message becomes a support conversation surfaced in the\nFilament admin panel, where an operator replies back through the bot.\n\nRoute: POST /api/telegram/webhook/support","summary":"Handle the public support bot webhook","tags":["TelegramWebhook"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},{"type":"null"},{"type":"object"}]}}}}}}},"/telegram/webhook/admin":{"post":{"operationId":"telegramWebhook.adminWebhook","description":"The bot's only job is to learn which chat to DM: any message links the\nsender's chat as the admin-notification destination.\n\nRoute: POST /api/telegram/webhook/admin","summary":"Handle the admin (private notifications) bot webhook","tags":["TelegramWebhook"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},{"type":"null"},{"type":"object"}]}}}}}}},"/telegram/webhook/client/{organization}":{"post":{"operationId":"telegramWebhook.orgClientWebhook","description":"Route: POST /api/telegram/webhook/client/{organization}","summary":"Handle organization-specific client bot webhook","tags":["TelegramWebhook"],"parameters":[{"name":"organization","in":"path","required":true,"description":"The organization ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},{"type":"null"},{"type":"object"}]}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["No custom bot configured"]}},"required":["error"]}}}},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/scraper/terms":{"post":{"operationId":"term.store","description":"Expects JSON body: { \"terms\": [{ \"term\", \"uz\", \"en\", \"kind\" }, ...] }\nAuth: Bearer token matching SCRAPER_API_TOKEN env var.","summary":"Import the ru -> uz/en dictionary for scraped directory strings","tags":["Term"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"terms":{"type":"array","items":{"type":"object","properties":{"term":{"type":"string","maxLength":500},"uz":{"type":["string","null"],"maxLength":500},"en":{"type":["string","null"],"maxLength":500},"kind":{"type":["string","null"],"maxLength":20}},"required":["term"]},"minItems":1}},"required":["terms"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"imported":{"type":"string"},"changed":{"type":"string"},"total":{"type":"string"}},"required":["message","imported","changed","total"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/transactions":{"get":{"operationId":"transaction.index","summary":"List all payment transactions for the organization","tags":["Transaction"],"parameters":[{"name":"page","in":"query","schema":{"type":["integer","null"],"minimum":1}},{"name":"per_page","in":"query","schema":{"type":["integer","null"],"minimum":1,"maximum":100}},{"name":"sort_by","in":"query","schema":{"type":["string","null"],"enum":["id","amount","state","provider","created_at","perform_time"]}},{"name":"sort_order","in":"query","schema":{"type":["string","null"],"enum":["asc","desc"]}},{"name":"search","in":"query","schema":{"type":["string","null"],"maxLength":255}},{"name":"state[]","in":"query","schema":{"type":"array","enum":["pending","prepared","completed","cancelled","refunded"],"items":{"type":"string","enum":["pending","prepared","completed","cancelled","refunded"]}}},{"name":"provider[]","in":"query","schema":{"type":"array","enum":["click","payme","stripe"],"items":{"type":"string","enum":["click","payme","stripe"]}}},{"name":"staff_id[]","in":"query","schema":{"type":"array","items":{"type":"integer"}}},{"name":"service_id[]","in":"query","schema":{"type":"array","items":{"type":"integer"}}},{"name":"client_id[]","in":"query","schema":{"type":"array","items":{"type":"integer"}}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Paginated set of `PaymentTransactionResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentTransactionResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/transactions/summary":{"get":{"operationId":"transaction.summary","summary":"Get revenue summary for the organization's transactions","tags":["Transaction"],"parameters":[{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Totals are integer MINOR units (tiyin for UZS); divide by 10^currency_scale.","content":{"application/json":{"schema":{"type":"object","properties":{"total_collected":{"type":"integer"},"total_refunded":{"type":"integer"},"total_pending":{"type":"integer"},"net_revenue":{"type":"integer"},"transaction_count":{"type":"string"},"currency":{"type":"string"},"currency_scale":{"type":"integer"}},"required":["total_collected","total_refunded","total_pending","net_revenue","transaction_count","currency","currency_scale"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/transactions/export":{"get":{"operationId":"transaction.export","summary":"Export transactions as CSV","tags":["Transaction"],"parameters":[{"name":"state[]","in":"query","schema":{"type":"array","enum":["pending","prepared","completed","cancelled","refunded"],"items":{"type":"string","enum":["pending","prepared","completed","cancelled","refunded"]}}},{"name":"provider[]","in":"query","schema":{"type":"array","enum":["click","payme","stripe"],"items":{"type":"string","enum":["click","payme","stripe"]}}},{"name":"from","in":"query","schema":{"type":["string","null"],"format":"date-time"}},{"name":"to","in":"query","schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"","content":{"text/csv":{"schema":{"type":"string"}}},"headers":{"Transfer-Encoding":{"required":true,"schema":{"type":"string","enum":["chunked"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/ai/translate":{"post":{"operationId":"translation.translate","description":"The owner reviews and edits the result in the form before saving, so nothing\nis persisted here. Tokens are billed to the organization's AI pool.","summary":"Suggest translations of business text fields into the requested locales","tags":["Translation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranslateRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"translations":{"type":"object","additionalProperties":{"type":"string"}}},"required":["translations"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"},"429":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}}},"/scraper/upload-media":{"post":{"operationId":"upload.upload","description":"Called by the scraper before import to pre-upload images. Returns stored\npaths that can be passed directly in the import JSON.\n\nFiles land in :class:`MediaPaths`' layout — one directory per\norganization id, filenames carrying the slug — so the caller still only\nhas to send a slug. When that slug matches no organization yet (push.py\nuploads media before the import that creates the row) the files go to a\npending directory and ``media:normalize`` moves them once an id exists.\n\nBehavior is additive per field — only the role being replaced is cleared:\n  - logo:         wipes the existing `*-logo.*`\n  - photos:       wipes existing `*-photo-N.*` (leaves logo/map/orientation)\n  - map_photo:    overwrites `*-map.png` only\n  - orientation:  wipes existing `*-orientation-N.*`","summary":"Upload media files for a business (logo + gallery photos + map photo)","tags":["Upload"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","maxLength":255},"logo":{"type":["string","null"]},"map_photo":{"type":["string","null"]},"append_photos":{"type":["boolean","null"]},"append_orientation":{"type":["boolean","null"]},"photos":{"type":["array","null"],"items":{"type":"string"}},"orientation":{"type":["array","null"],"items":{"type":"string"}}},"required":["slug"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"logo":{"type":"string"},"photos":{"type":"array","prefixItems":[{"type":"string"}],"minItems":1,"maxItems":1,"additionalItems":false},"map_photo":{"type":"string"},"orientation":{"type":"array","prefixItems":[{"type":"string"}],"minItems":1,"maxItems":1,"additionalItems":false}},"required":["logo","photos","map_photo","orientation"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/payment/uzum/callback":{"post":{"operationId":"uzumCallback.handle","tags":["UzumCallback"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string"},"params":{"type":"string"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string","enum":["Internal server error"]}},"required":["code","message"]}},"required":["error"]},{"type":"string"}]}}}}}}},"/org/voice/calls":{"get":{"operationId":"voiceCall.index","description":"The query is validated rather than read ad hoc off the request, because\nthat is also the only thing Scramble can see: `page` is consumed by\n`paginate()` and never named in the method, so the generated client had\nno way to ask for page two.","summary":"The calls the receptionist handled","tags":["VoiceCall"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","schema":{"type":"string","maxLength":120}},{"name":"outcome","in":"query","schema":{"type":"string","maxLength":32}},{"name":"channel","in":"query","schema":{"type":"string","maxLength":32}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"channel":{"type":"string"},"direction":{"type":"string"},"status":{"type":"string"},"outcome":{"type":["string","null"]},"locale":{"type":["string","null"]},"caller_name":{"type":["string","null"]},"from_number":{"type":["string","null"]},"started_at":{"type":["string","null"]},"duration_seconds":{"type":["integer","null"]},"turn_count":{"type":"integer"},"cost_som":{"type":"number"},"appointment_id":{"type":["integer","null"]},"summary":{"type":["string","null"]}},"required":["id","channel","direction","status","outcome","locale","caller_name","from_number","started_at","duration_seconds","turn_count","cost_som","appointment_id","summary"]}},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"last_page":{"type":"integer"},"total":{"type":"integer"}},"required":["current_page","last_page","total"]}},"required":["data","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/voice/calls/stats":{"get":{"operationId":"voiceCall.stats","summary":"The headline numbers, in so'm rather than tokens","tags":["VoiceCall"],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":365}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"window_days":{"type":"integer"},"calls":{"type":"integer"},"booked":{"type":"integer"},"escalated":{"type":"integer"},"messages_taken":{"type":"integer"},"revenue_som":{"type":"number"},"cost_som":{"type":"number"},"median_first_response_ms":{"type":["integer","null"]}},"required":["window_days","calls","booked","escalated","messages_taken","revenue_som","cost_som","median_first_response_ms"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/voice/calls/{call}":{"get":{"operationId":"voiceCall.show","summary":"One call, with its transcript and everything the receptionist did","tags":["VoiceCall"],"parameters":[{"name":"call","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"call":{"type":"object","properties":{"id":{"type":"string"},"channel":{"type":"string"},"direction":{"type":"string"},"status":{"type":"string"},"outcome":{"type":["string","null"]},"locale":{"type":["string","null"]},"caller_name":{"type":["string","null"]},"from_number":{"type":["string","null"]},"started_at":{"type":["string","null"]},"duration_seconds":{"type":["integer","null"]},"turn_count":{"type":"integer"},"cost_som":{"type":"number"},"appointment_id":{"type":["integer","null"]},"summary":{"type":["string","null"]}},"required":["id","channel","direction","status","outcome","locale","caller_name","from_number","started_at","duration_seconds","turn_count","cost_som","appointment_id","summary"]},"summary":{"type":["string","null"]},"meta":{"type":["object","null"],"additionalProperties":{}},"transcript":{"type":"array","items":{"type":"object","properties":{"sequence":{"type":"integer"},"role":{"type":"string"},"text":{"type":["string","null"]},"language":{"type":["string","null"]},"latency_ms":{"type":["integer","null"]},"transcript_is_evidence":{"type":"boolean"},"tools":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"label":{"type":["string","null"]},"label_key":{"type":["string","null"]},"label_params":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"}]}},"ok":{"type":["boolean","null"]}},"required":["name","label","label_key","label_params","ok"]}}},"required":["sequence","role","text","language","latency_ms","transcript_is_evidence","tools"]}},"appointment":{"type":["object","null"],"properties":{"id":{"type":"integer"},"status":{"type":"string"},"service":{"type":["string","null"]},"staff":{"type":["string","null"]},"starts_at":{"type":["string","null"]}},"required":["id","status","service","staff","starts_at"]}},"required":["call","summary","meta","transcript","appointment"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/voice/demo/config":{"get":{"operationId":"voiceDemo.config","summary":"Everything the demo page needs to render before anyone speaks: which\nbusiness is answering, what it sells, who works there","tags":["VoiceDemo"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"organization":{"type":"object","properties":{"name":{"type":"string"},"city":{"type":["string","null"]},"address":{"type":["string","null"]},"timezone":{"type":"string"},"local_time":{"type":"string"},"currency":{"type":"string"}},"required":["name","city","address","timezone","local_time","currency"]},"receptionist":{"type":"object","properties":{"primary_locale":{"type":"string"},"locales":{"type":"array","items":{"type":"string"}},"voice_gender":{"type":["string","null"]},"greeting":{"type":"string"},"can_book":{"type":"boolean"},"voice_driver":{"type":"string"}},"required":["primary_locale","locales","voice_gender","greeting","can_book","voice_driver"]},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"duration":{"type":"integer"},"price":{"type":["number","null"]}},"required":["name","duration","price"]}},"staff":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"position":{"type":["string","null"]}},"required":["name","position"]}}},"required":["organization","receptionist","services","staff"]}}}}}}},"/voice/demo/start":{"post":{"operationId":"voiceDemo.start","summary":"Pick up the phone: opens a call and streams back the spoken greeting","tags":["VoiceDemo"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/voice/demo/turn":{"post":{"operationId":"voiceDemo.turn","summary":"One caller turn: audio (or typed text) in, spoken reply streaming out","tags":["VoiceDemo"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"call_id":{"type":"string","format":"uuid"},"secret":{"type":"string"},"audio":{"type":["string","null"],"format":"binary","contentMediaType":"application/octet-stream","description":"8MB is about two minutes of Opus, far longer than any single\nutterance; anything above it is not someone talking.","maxLength":8192},"text":{"type":["string","null"],"maxLength":1000}},"required":["call_id","secret"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/voice/demo/end":{"post":{"operationId":"voiceDemo.end","summary":"Hang up, and hand back everything the call produced — the transcript, the\nappointment if there is one, and what it cost. That summary is the demo's\nactual punchline, so it is a first-class response rather than a footnote","tags":["VoiceDemo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"call_id":{"type":"string","format":"uuid"},"secret":{"type":"string"}},"required":["call_id","secret"]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"call":{"type":"object","properties":{"id":{"type":"string"},"duration_seconds":{"type":["integer","null"]},"turns":{"type":"integer"},"outcome":{"type":["string","null"]},"locale":{"type":["string","null"]},"cost_som":{"type":"number"}},"required":["id","duration_seconds","turns","outcome","locale","cost_som"]},"transcript":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"text":{"type":["string","null"]},"language":{"type":["string","null"]},"latency_ms":{"type":["integer","null"]},"tools":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"label":{"type":["string","null"]},"label_key":{"type":["string","null"]},"label_params":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"}]}},"ok":{"type":["boolean","null"]}},"required":["name","label","label_key","label_params","ok"]}}},"required":["role","text","language","latency_ms","tools"]}},"appointment":{"type":["object","null"],"properties":{"id":{"type":"integer"},"status":{"type":"string"},"service":{"type":["string","null"]},"staff":{"type":["string","null"]},"starts_at":{"type":["string","null"]}},"required":["id","status","service","staff","starts_at"]}},"required":["call","transcript","appointment"]}}}},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/voice/settings":{"get":{"operationId":"voiceSetting.show","tags":["VoiceSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean"},"primary_locale":{"type":"string"},"allowed_locales":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","prefixItems":[{"type":"string","enum":["uz"]},{"type":"string","enum":["ru"]},{"type":"string","enum":["en"]}],"minItems":3,"maxItems":3,"additionalItems":false}]},"voice_gender":{"type":"string"},"voice_id":{"type":["string","null"]},"politeness":{"type":"string"},"greeting":{"type":["string","null"]},"house_rules":{"type":["string","null"]},"vocabulary":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"can_book":{"type":"boolean"},"can_cancel":{"type":"boolean"},"can_reschedule":{"type":"boolean"},"escalation_targets":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"max_concurrent_calls":{"type":"integer"}},"required":["enabled","primary_locale","allowed_locales","voice_gender","voice_id","politeness","greeting","house_rules","vocabulary","can_book","can_cancel","can_reschedule","escalation_targets","max_concurrent_calls"]},"defaults":{"type":"object","properties":{"greeting":{"type":"string"},"voices":{"type":"array","items":{"type":"string"}}},"required":["greeting","voices"]},"platform_enabled":{"type":"boolean","description":"The organization flag alone does not switch it on; the platform\nflag has to be on too, and an owner staring at an enabled toggle\nthat does nothing deserves to be told which one is missing."}},"required":["settings","defaults","platform_enabled"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"put":{"operationId":"voiceSetting.update","tags":["VoiceSetting"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"primary_locale":{"type":"string","enum":["uz","ru","en"]},"voice_gender":{"type":"string","enum":["female","male"]},"voice_id":{"type":["string","null"],"maxLength":120},"politeness":{"type":"string","enum":["siz","sen"]},"greeting":{"type":["string","null"],"maxLength":500},"house_rules":{"type":["string","null"],"maxLength":4000},"can_book":{"type":"boolean"},"can_cancel":{"type":"boolean"},"can_reschedule":{"type":"boolean"},"escalation_targets":{"type":["array","null"],"items":{"type":"string"},"maxItems":10},"max_concurrent_calls":{"type":"integer","minimum":1,"maximum":50},"allowed_locales":{"type":"array","items":{"type":"string","enum":["uz","ru","en"]}},"vocabulary":{"type":["array","null"],"items":{"type":"object","properties":{"heard":{"type":["string","null"],"maxLength":120},"means":{"type":"string","maxLength":120}}},"maxItems":200}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean"},"primary_locale":{"type":"string"},"allowed_locales":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","prefixItems":[{"type":"string","enum":["uz"]},{"type":"string","enum":["ru"]},{"type":"string","enum":["en"]}],"minItems":3,"maxItems":3,"additionalItems":false}]},"voice_gender":{"type":"string"},"voice_id":{"type":["string","null"]},"politeness":{"type":"string"},"greeting":{"type":["string","null"]},"house_rules":{"type":["string","null"]},"vocabulary":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"can_book":{"type":"boolean"},"can_cancel":{"type":"boolean"},"can_reschedule":{"type":"boolean"},"escalation_targets":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"max_concurrent_calls":{"type":"integer"}},"required":["enabled","primary_locale","allowed_locales","voice_gender","voice_id","politeness","greeting","house_rules","vocabulary","can_book","can_cancel","can_reschedule","escalation_targets","max_concurrent_calls"]}},"required":["settings"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/voice/settings/seed-vocabulary":{"post":{"operationId":"voiceSetting.seedVocabulary","description":"This is the highest-leverage single action an owner can take: staff names\nand service names in local spelling are what the model mishears, and\nhanding it this list is worth more than changing model. Offering it as\none button beats asking an owner to type forty names.","summary":"Seed the vocabulary from the business's own data","tags":["VoiceSetting"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"integer"},"settings":{"type":"object","properties":{"enabled":{"type":"boolean"},"primary_locale":{"type":"string"},"allowed_locales":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","prefixItems":[{"type":"string","enum":["uz"]},{"type":"string","enum":["ru"]},{"type":"string","enum":["en"]}],"minItems":3,"maxItems":3,"additionalItems":false}]},"voice_gender":{"type":"string"},"voice_id":{"type":["string","null"]},"politeness":{"type":"string"},"greeting":{"type":["string","null"]},"house_rules":{"type":["string","null"]},"vocabulary":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"can_book":{"type":"boolean"},"can_cancel":{"type":"boolean"},"can_reschedule":{"type":"boolean"},"escalation_targets":{"anyOf":[{"type":"array","items":{}},{"type":"null"},{"type":"array","items":{"type":"string"},"minItems":0,"maxItems":0,"additionalItems":false}]},"max_concurrent_calls":{"type":"integer"}},"required":["enabled","primary_locale","allowed_locales","voice_gender","voice_id","politeness","greeting","house_rules","vocabulary","can_book","can_cancel","can_reschedule","escalation_targets","max_concurrent_calls"]}},"required":["added","settings"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/waitlist":{"get":{"operationId":"waitlist.index","summary":"List waitlist entries for the organization","tags":["Waitlist"],"responses":{"200":{"description":"Paginated set of `WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer"},"from":{"type":["integer","null"]},"last_page":{"type":"integer"},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page."},"to":{"type":["integer","null"],"description":"Number of the last item in the slice."},"total":{"type":"integer","description":"Total number of items being paginated."}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}},"post":{"operationId":"waitlist.store","summary":"Add a client to the waitlist (staff action)","tags":["Waitlist"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreWaitlistEntryRequest"}}}},"responses":{"200":{"description":"`WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/waitlist/summary":{"get":{"operationId":"waitlist.summary","summary":"Get waitlist summary counts by status","tags":["Waitlist"],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"waiting":{"type":"string"},"offered":{"type":"string"},"booked":{"type":"string"},"expired":{"type":"string"},"cancelled":{"type":"string"},"total_active":{"type":"string"}},"required":["waiting","offered","booked","expired","cancelled","total_active"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"}}}},"/org/waitlist/{waitlistEntry}":{"get":{"operationId":"waitlist.show","summary":"Show a single waitlist entry","tags":["Waitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}},"/org/waitlist/{waitlistEntry}/offer":{"post":{"operationId":"waitlist.offer","summary":"Offer a specific slot to a waitlisted client (manual promote)","tags":["Waitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferWaitlistSlotRequest"}}}},"responses":{"200":{"description":"`WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"},"422":{"$ref":"#/components/responses/ValidationException"}}}},"/org/waitlist/{waitlistEntry}/cancel":{"post":{"operationId":"waitlist.cancel","summary":"Cancel a waitlist entry (staff action)","tags":["Waitlist"],"parameters":[{"name":"waitlistEntry","in":"path","required":true,"description":"The waitlist entry ID","schema":{"type":"integer"}}],"responses":{"200":{"description":"`WaitlistEntryResource`","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntryResource"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/AuthenticationException"},"404":{"$ref":"#/components/responses/ModelNotFoundException"}}}}},"components":{"schemas":{"AddClaimDocumentsRequest":{"type":"object","properties":{"documents":{"type":"array","items":{"type":"object","properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","maxLength":10240},"kind":{"type":"string","enum":["registration_cert","tax_cert","license","lease","utility_bill","other"]}},"required":["file","kind"]},"minItems":1,"maxItems":5}},"required":["documents"],"title":"AddClaimDocumentsRequest"},"AnnouncementResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"title":{"type":"string"},"content":{"type":["string","null"]},"translations":{"type":"object","properties":{"title":{"type":"object","additionalProperties":{"type":"string"}},"content":{"type":"object","additionalProperties":{"type":"string"}}},"required":["title","content"]},"type":{"type":"string"},"target":{"type":"string"},"is_active":{"type":"boolean"},"publish_at":{"type":"string"},"expire_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","organization_id","title","content","translations","type","target","is_active","publish_at","expire_at","created_at","updated_at"],"title":"AnnouncementResource"},"App.Http.Requests.Api.Client.CancelAppointmentRequest":{"type":"object","properties":{"reason":{"type":["string","null"],"maxLength":500}},"title":"App.Http.Requests.Api.Client.CancelAppointmentRequest"},"App.Http.Requests.Api.Client.RescheduleAppointmentRequest":{"type":"object","properties":{"start_time":{"type":"string","format":"date-time"}},"required":["start_time"],"title":"App.Http.Requests.Api.Client.RescheduleAppointmentRequest"},"App.Http.Resources.Api.Ai.ConversationResource":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":["string","null"]},"status":{"type":"string"},"started_at":{"type":"string"},"last_message_at":{"type":"string"},"message_count":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessageResource"}}},"required":["id","title","status","started_at","last_message_at","message_count","messages"],"title":"App.Http.Resources.Api.Ai.ConversationResource"},"AppointmentResource":{"type":"object","properties":{"id":{"type":"integer"},"startDate":{"type":["string","null"]},"endDate":{"type":["string","null"]},"start_time":{"type":["string","null"]},"end_time":{"type":["string","null"]},"title":{"type":"string"},"description":{"type":"string"},"notes":{"type":["string","null"]},"status":{"type":"string"},"payment_status":{"type":"string"},"price_snapshot":{"type":["string","null"]},"currency":{"type":"string"},"cancellation_reason":{"type":["string","null"]},"payment_expires_at":{"type":"string"},"color":{"type":"string","enum":["green","yellow","red","blue","orange","gray"]},"user":{"type":"object","description":"Client info (for org dashboard)","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"string","enum":["Unknown Client"]}]},"picturePath":{"type":"null"}},"required":["id","name","picturePath"]},"client":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}},"required":["id","name","email","phone"]},"service":{"type":"object","description":"Service info","properties":{"id":{"type":"integer"},"name":{"type":"string"},"duration":{"type":"integer"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"description":"Staff info","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"branch":{"type":["object","null"],"description":"Branch info","properties":{"id":{"type":"integer"},"name":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"phone":{"type":["string","null"]},"latitude":{"type":["string","null"]},"longitude":{"type":["string","null"]}},"required":["id","name","address","city","phone","latitude","longitude"]},"organization":{"type":"object","description":"Organization info (for client dashboard)","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]},"country":{"type":["string","null"],"description":"ISO-3166 alpha-2 country code, e.g. \"UZ\""},"canonical_path":{"type":"string","description":"The venue's canonical path, WITHOUT a locale prefix —\n`/tashkent/barber/britva` (ODI-182). Appointments are the one surface that links back to a\nvenue while holding nothing but a slug, and the flat\n`/{slug}` form 404s now. Rather than shipping the city\nand category separately and re-deriving the path in three\nclient components, the backend hands over the finished\npath it already computes for the venue page itself."}},"required":["id","name","slug","logo","country","canonical_path"]},"review":{"type":["object","null"],"description":"Review info (for client history)","properties":{"id":{"type":"integer"},"rating":{"type":"integer"},"comment":{"type":["string","null"]}},"required":["id","rating","comment"]},"has_review":{"type":"boolean"},"can_cancel":{"type":"boolean"},"can_reschedule":{"type":"boolean"},"can_review":{"type":"boolean"},"cancellation_deadline":{"type":["string","null"],"description":"ISO 8601 deadline for cancellation"},"reschedule_deadline":{"type":["string","null"],"description":"ISO 8601 deadline for rescheduling"},"cancellation_policy":{"type":["object","null"],"properties":{"cancellation_min_hours":{"type":"integer"},"reschedule_min_hours":{"type":"integer"}},"required":["cancellation_min_hours","reschedule_min_hours"]},"client_id":{"type":"integer","description":"Legacy fields"},"service_id":{"type":["integer","null"]},"staff_id":{"type":["integer","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","startDate","endDate","start_time","end_time","title","description","notes","status","payment_status","price_snapshot","currency","cancellation_reason","payment_expires_at","color","user","has_review","can_cancel","can_reschedule","can_review","cancellation_deadline","reschedule_deadline","cancellation_policy","client_id","service_id","staff_id","created_at","updated_at"],"title":"AppointmentResource"},"ApproveJoinRequest":{"type":"object","properties":{"roles":{"type":["array","null"],"items":{"type":"string","enum":["owner","manager","service_provider","receptionist"]}}},"title":"ApproveJoinRequest"},"AssignStaffToServiceRequest":{"type":"object","properties":{"staff_ids":{"type":"array","items":{"type":"integer"}}},"required":["staff_ids"],"title":"AssignStaffToServiceRequest"},"BatchDestroyAppointmentsRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchDestroyAppointmentsRequest"},"BatchDestroyClientsRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchDestroyClientsRequest"},"BatchDestroyServicesRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchDestroyServicesRequest"},"BatchDestroyStaffRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchDestroyStaffRequest"},"BatchUpdateAppointmentsRequest":{"type":"object","properties":{"status":{"type":"string","enum":["pending","confirmed","completed","cancelled","no_show"]},"staff_id":{"type":["integer","null"]},"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchUpdateAppointmentsRequest"},"BatchUpdateClientsRequest":{"type":"object","properties":{"is_active":{"type":"boolean"},"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchUpdateClientsRequest"},"BatchUpdateServicesRequest":{"type":"object","properties":{"is_active":{"type":"boolean"},"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchUpdateServicesRequest"},"BatchUpdateStaffRequest":{"type":"object","properties":{"is_active":{"type":"boolean"},"ids":{"type":"array","items":{"type":"integer"},"minItems":1}},"required":["ids"],"title":"BatchUpdateStaffRequest"},"BookAppointmentRequest":{"type":"object","properties":{"service_id":{"type":"integer"},"staff_id":{"type":["integer","null"]},"branch_id":{"type":["integer","null"]},"start_time":{"type":"string","format":"date-time"},"name":{"type":"string","maxLength":255},"email":{"type":["string","null"],"format":"email","maxLength":255},"phone":{"type":["string","null"],"maxLength":50},"notes":{"type":["string","null"],"maxLength":500},"telegram_init_data":{"type":["string","null"]},"verification_code":{"type":["string","null"],"description":"Issued by POST /client/booking/{slug}/request-code. Required for\nguests (see below); ignored for authenticated and Telegram users.","minLength":6,"maxLength":6}},"required":["service_id","start_time","name"],"title":"BookAppointmentRequest"},"Branch":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"name":{"type":"array","items":{}},"address":{"type":"array","items":{}},"city":{"type":"string"},"state":{"type":["string","null"]},"country":{"type":"string"},"phone":{"type":["string","null"]},"latitude":{"type":["string","null"]},"longitude":{"type":["string","null"]},"is_main":{"type":"boolean"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"deleted_at":{"type":["string","null"],"format":"date-time"},"district":{"type":["string","null"]},"city_id":{"type":["integer","null"]},"region_id":{"type":["integer","null"]},"location":{"type":["string","null"]}},"required":["id","organization_id","name","address","city","state","country","phone","latitude","longitude","is_main","created_at","updated_at","deleted_at","district","city_id","region_id","location"],"title":"Branch"},"BranchResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"name":{"type":"string"},"address":{"type":"string"},"translations":{"type":"object","properties":{"name":{"type":"object","additionalProperties":{"type":"string"}},"address":{"type":"object","additionalProperties":{"type":"string"}}},"required":["name","address"]},"district":{"type":["string","null"]},"city":{"type":["string","null"],"description":"Translated city name (locale-aware), falls back to the stored string"},"state":{"type":["string","null"],"description":"Translated region name (locale-aware), falls back to the stored string"},"country":{"type":"string"},"phone":{"type":["string","null"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"is_main":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","organization_id","name","address","translations","district","city","state","country","phone","latitude","longitude","is_main","created_at","updated_at"],"title":"BranchResource"},"CalendarConnectionResource":{"type":"object","properties":{"id":{"type":"integer"},"provider":{"type":"string"},"provider_email":{"type":["string","null"]},"calendar_id":{"type":"string"},"sync_enabled":{"type":"boolean"},"push_enabled":{"type":"boolean"},"pull_enabled":{"type":"boolean"},"last_synced_at":{"type":"string"},"created_at":{"type":"string"}},"required":["id","provider","provider_email","calendar_id","sync_enabled","push_enabled","pull_enabled","last_synced_at","created_at"],"title":"CalendarConnectionResource"},"CancelAppointmentRequest":{"type":"object","properties":{"reason":{"type":["string","null"],"maxLength":500}},"title":"CancelAppointmentRequest"},"Category":{"type":"object","properties":{"id":{"type":"integer"},"parent_id":{"type":["integer","null"]},"name":{"type":"array","items":{}},"slug":{"type":"string"},"icon":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"illustration":{"type":["string","null"]},"cover_image":{"type":["string","null"]}},"required":["id","parent_id","name","slug","icon","created_at","updated_at","illustration","cover_image"],"title":"Category"},"ChatMessageResource":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string"},"content":{"type":"string"},"created_at":{"type":"string"}},"required":["id","role","content","created_at"],"title":"ChatMessageResource"},"CheckoutSubscriptionRequest":{"type":"object","properties":{"tier":{"type":"string","enum":["avtopilot"]},"extra_branches":{"type":"integer","minimum":0,"maximum":50}},"required":["tier"],"title":"CheckoutSubscriptionRequest"},"ClaimRequestResource":{"type":"object","properties":{"id":{"type":"string"},"organization_id":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"business_name":{"type":["string","null"]},"logo":{"type":"string"},"city":{"type":"string"},"address":{"type":"string"}},"required":["id","slug","business_name","logo","city","address"]},"status":{"type":"string"},"status_label":{"type":"string"},"applicant_role":{"type":"string"},"applicant_name":{"type":"string"},"applicant_phone":{"type":"string"},"applicant_email":{"type":"string"},"message":{"type":"string"},"decision_reason":{"type":"string"},"requested_documents":{"type":"array","items":{"type":"string"}},"requested_document_labels":{"type":"array","items":{"type":"string"}},"documents_request_note":{"type":"string"},"documents_requested_at":{"type":"string"},"documents_resubmitted_at":{"type":"string"},"submitted_at":{"type":"string"},"reviewed_at":{"type":"string"},"withdrawn_at":{"type":"string"},"seen_at":{"type":"string"},"telegram_linked":{"type":"boolean","description":"Whether the applicant's Telegram is connected, so updates reach them there."},"telegram_ref":{"type":"string","description":"The `?start=` value of the sales-bot link on the claim page."},"documents":{"type":"string"}},"required":["id","organization_id","status","status_label","applicant_role","applicant_name","applicant_phone","applicant_email","message","decision_reason","requested_documents","requested_document_labels","documents_request_note","documents_requested_at","documents_resubmitted_at","submitted_at","reviewed_at","withdrawn_at","seen_at","telegram_linked","telegram_ref"],"title":"ClaimRequestResource"},"ClientNotificationSettingResource":{"type":"object","properties":{"email":{"type":"boolean"},"sms":{"type":"boolean"},"telegram":{"type":"boolean"},"database":{"type":"boolean"}},"required":["email","sms","telegram","database"],"title":"ClientNotificationSettingResource"},"ClientResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"user_id":{"type":["integer","null"]},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"telegram_user_id":{"type":["string","null"]},"notes":{"type":["string","null"]},"notification_preferences":{"type":["object","null"],"description":"Per-channel opt-outs; null means every channel is enabled.","additionalProperties":{"type":"boolean"}},"created_at":{"type":"string"},"updated_at":{"type":"string"},"appointments_count":{"type":"integer","description":"Present on the list endpoint only."},"last_visit":{"type":["string","null"],"description":"Start time (ISO 8601) of the latest completed visit. Present on the list endpoint only."},"next_visit":{"type":["string","null"],"description":"Start time (ISO 8601) of the next pending/confirmed visit. Present on the list endpoint only."}},"required":["id","organization_id","user_id","name","email","phone","telegram_user_id","notes","notification_preferences","created_at","updated_at"],"title":"ClientResource"},"ConnectTelegramBotRequest":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"],"title":"ConnectTelegramBotRequest"},"ConversationResource":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string"},"unread_count":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]}},"required":["id","name","slug","logo"]},"client":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"last_message":{"type":["object","null"],"properties":{"id":{"type":"string"},"content":{"type":"string"},"is_from_client":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","content","is_from_client","created_at"]}},"required":["id","status","unread_count","created_at","updated_at"],"title":"ConversationResource"},"CreateAnnouncementRequest":{"type":"object","properties":{"type":{"type":"string","enum":["info","warning","critical"]},"target":{"type":"string","enum":["all_clients","recent_clients"]},"is_active":{"type":"boolean"},"publish_at":{"type":["string","null"],"format":"date-time"},"expire_at":{"type":["string","null"],"format":"date-time"},"title":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"content":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":5000},"uz":{"type":["string","null"],"maxLength":5000},"ru":{"type":["string","null"],"maxLength":5000}}}},"required":["title"],"title":"CreateAnnouncementRequest"},"CreateBranchRequest":{"type":"object","properties":{"phone":{"type":["string","null"],"maxLength":20},"district":{"type":["string","null"],"maxLength":255},"city":{"type":["string","null"],"maxLength":255},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"is_main":{"type":"boolean"},"name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"address":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":500},"uz":{"type":["string","null"],"maxLength":500},"ru":{"type":["string","null"],"maxLength":500}}}},"required":["name","address"],"title":"CreateBranchRequest"},"CreateClientRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"phone":{"type":["string","null"],"maxLength":20},"email":{"type":["string","null"],"format":"email","maxLength":255},"notes":{"type":["string","null"]}},"required":["name"],"title":"CreateClientRequest"},"CreateOrganizationRequest":{"type":"object","properties":{"slug":{"type":"string","maxLength":50},"city_id":{"type":["integer","null"],"description":"Location, chosen in the wizard rather than inferred: `city_id` is the\ncanonical city the whole catalog groups by (a venue without it has no\n/{city}/{category}/{venue} URL and never reaches a city landing page),\nand the coordinates come from the map pin the owner drops."},"district":{"type":["string","null"],"maxLength":100},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"country":{"type":["string","null"],"maxLength":10},"phone":{"type":["string","null"],"maxLength":50},"email":{"type":["string","null"],"format":"email","maxLength":255},"website":{"type":["string","null"],"format":"uri","maxLength":255},"use_contact_for_account":{"type":["boolean","null"],"description":"Opt-in: copy the business phone/email onto the owner's own account\nwhen it has none. A Telegram Mini App signup arrives with neither,\nand the web dashboard can only be signed into with an email."},"default_currency":{"type":["string","null"],"minLength":3,"maxLength":3},"referral_code":{"type":["string","null"],"maxLength":10},"partner_code":{"type":["string","null"],"maxLength":20},"tracking_token":{"type":["string","null"],"description":"The flyer or promoter code from the `bj_tk` cookie. A malformed one is ignored.","maxLength":255},"business_name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"specialty":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"description":{"type":"object","properties":{"en":{"type":["string","null"]},"uz":{"type":["string","null"]},"ru":{"type":["string","null"]}}},"address":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"map_import":{"type":"object","properties":{"source":{"type":"string","enum":["google","2gis","yandex"]},"source_id":{"type":"string","maxLength":255},"source_url":{"type":["string","null"],"format":"uri","maxLength":500},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"city":{"type":["string","null"],"maxLength":255},"district":{"type":["string","null"],"maxLength":255},"country":{"type":["string","null"],"maxLength":10},"business_hours":{"type":["array","null"],"items":{"type":"string"}},"social_links":{"type":["array","null"],"items":{"type":"string","format":"uri"}},"photos":{"type":["array","null"],"items":{"type":"string","format":"uri"}},"rating":{"type":["number","null"],"minimum":0,"maximum":5},"review_count":{"type":["integer","null"],"minimum":0},"categories":{"type":["array","null"],"items":{"type":"string","maxLength":100}}}}},"required":["slug","business_name"],"title":"CreateOrganizationRequest"},"CreateReviewRequest":{"type":"object","properties":{"appointment_id":{"type":"integer"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":["string","null"],"maxLength":1000},"is_public":{"type":"boolean"}},"required":["appointment_id","rating"],"title":"CreateReviewRequest"},"CreateServiceRequest":{"type":"object","properties":{"duration":{"type":"integer"},"price":{"type":"number"},"prepay_policy":{"type":["string","null"],"enum":["none","partial","full"]},"prepay_percentage":{"type":["integer","null"],"minimum":1,"maximum":100},"name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":1000},"uz":{"type":["string","null"],"maxLength":1000},"ru":{"type":["string","null"],"maxLength":1000}}},"staff_ids":{"type":["array","null"],"items":{"type":"integer"}}},"required":["duration","price","name"],"title":"CreateServiceRequest"},"CreateStaffRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"slug":{"type":["string","null"],"maxLength":255},"avatar":{"type":["string","null"]},"email":{"type":"string","format":"email"},"phone":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_profile_public":{"type":"boolean"},"display_name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"position":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"bio":{"type":"object","properties":{"en":{"type":["string","null"]},"uz":{"type":["string","null"]},"ru":{"type":["string","null"]}}},"meta_title":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"meta_description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":500},"uz":{"type":["string","null"],"maxLength":500},"ru":{"type":["string","null"],"maxLength":500}}},"roles":{"type":"array","items":{"type":"string","enum":["owner","manager","service_provider","receptionist"]}},"service_ids":{"type":["array","null"],"items":{"type":"integer"}}},"required":["name","email"],"title":"CreateStaffRequest"},"DashboardResource":{"type":"object","properties":{"range":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]},"stats":{"type":"object","properties":{"total_revenue":{"type":"number"},"revenue_trend":{"type":"number"},"appointments":{"type":"integer"},"appointments_trend":{"type":"number"},"new_clients":{"type":"integer"},"new_clients_trend":{"type":"number"},"completion_rate":{"type":"number"},"completion_rate_trend":{"type":"number"}},"required":["total_revenue","revenue_trend","appointments","appointments_trend","new_clients","new_clients_trend","completion_rate","completion_rate_trend"]},"chart":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"appointments":{"type":"integer"}},"required":["date","appointments"]}}},"required":["range","stats","chart"],"title":"DashboardResource"},"FavoriteResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"created_at":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]},"specialty":{"type":["string","null"]},"district":{"type":["string","null"],"description":"Russian 2GIS adm_div, resolved through the directory dictionary."},"city":{"type":"string","description":"`organizations.city` is the canonical ENGLISH name; the\ntranslated display name lives on the city row."},"city_slug":{"type":["string","null"],"description":"The city SEGMENT of the venue URL (ODI-182), not the\ndisplay name — `cities.slug`, identical in every locale.\nA favorites card links to\n`/{locale}/{city}/{category}/{venue}`; without this it\nfalls back to the flat `/{venue}`, which 404s."},"primary_category":{"type":["object","null"],"description":"The other URL segment. `locale_slug` is what the path\nanswers on; `slug` is the catalog-wide canonical id. Same\nvalue in every language — the segment does not translate.","properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"}},"required":["slug","locale_slug"]},"address":{"type":["array","null"],"items":{}}},"required":["id","business_name","slug","logo","specialty","district","city","city_slug","address"]},"profile":{"type":["object","null"],"properties":{"average_rating":{"type":"string"},"total_reviews":{"type":"integer"},"cover_image":{"type":["string","null"]}},"required":["average_rating","total_reviews","cover_image"]}},"required":["id","organization_id","created_at"],"title":"FavoriteResource"},"InitiateClientPaymentRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["click","payme","stripe","uzum"]}},"required":["provider"],"title":"InitiateClientPaymentRequest"},"InitiatePaymentRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["click","payme","stripe","uzum"]},"amount":{"type":"integer","minimum":1}},"required":["provider","amount"],"title":"InitiatePaymentRequest"},"JoinWaitlistRequest":{"type":"object","properties":{"service_id":{"type":"integer"},"staff_id":{"type":["integer","null"]},"preferred_date":{"type":"string","format":"date-time"},"preferred_time_slot":{"type":["string","null"],"enum":["morning","afternoon","evening"]},"notes":{"type":["string","null"],"maxLength":500},"name":{"type":["string","null"],"maxLength":255},"email":{"type":["string","null"],"format":"email"},"phone":{"type":["string","null"],"minLength":10},"telegram_init_data":{"type":["string","null"]}},"required":["service_id","preferred_date"],"title":"JoinWaitlistRequest"},"MapSearchRequest":{"type":"object","properties":{"query":{"type":"string","minLength":2,"maxLength":200},"location":{"type":["string","null"],"maxLength":200},"limit":{"type":["integer","null"],"minimum":1,"maximum":10},"sources":{"type":["array","null"],"items":{"type":"string","enum":["google","2gis","yandex"]}}},"required":["query"],"title":"MapSearchRequest"},"MessageResource":{"type":"object","properties":{"id":{"type":"integer"},"content":{"type":"string"},"channel":{"type":"string"},"is_read":{"type":"boolean"},"is_from_client":{"type":"boolean"},"sender_type":{"type":"string","enum":["client","staff"]},"created_at":{"type":"string"}},"required":["id","content","channel","is_read","is_from_client","sender_type","created_at"],"title":"MessageResource"},"NotificationCategoryResource":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"owner_only":{"type":"boolean"}},"required":["value","label","owner_only"],"title":"NotificationCategoryResource"},"NotificationDeliveryOptionResource":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"title":"NotificationDeliveryOptionResource"},"NotificationEventResource":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"category":{"type":"string"},"tier":{"type":"string"},"audience":{"type":"string"},"default_delivery":{"type":"string"},"owner_only":{"type":"boolean","description":"Billing and client payments never reach a non-owner."},"mandatory":{"type":"boolean","description":"Critical events can be moved to the digest but not silenced, so\nthe UI hides \"Never\" for these."},"digest_only":{"type":"boolean"}},"required":["value","label","category","tier","audience","default_delivery","owner_only","mandatory","digest_only"],"title":"NotificationEventResource"},"NotificationResource":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"icon":{"type":"string"},"action_url":{"type":["string","null"]},"meta":{"type":"object","additionalProperties":{}},"is_read":{"type":"boolean"},"read_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","type","title","body","icon","action_url","meta","is_read","read_at","created_at"],"title":"NotificationResource"},"OfferWaitlistSlotRequest":{"type":"object","properties":{"start_time":{"type":"string","format":"date-time"}},"required":["start_time"],"title":"OfferWaitlistSlotRequest"},"OrgLoginRequest":{"type":"object","properties":{"identifier":{"type":"string"},"identifier_type":{"type":"string","enum":["email","phone"]},"auth_method":{"type":"string","enum":["password","code"]},"password":{"type":["string","null"]}},"required":["identifier","identifier_type","auth_method"],"title":"OrgLoginRequest"},"OrgProfileUpdateRequest":{"type":"object","properties":{"business_name":{"type":"string","maxLength":255},"specialty":{"type":"string","maxLength":255}},"required":["business_name","specialty"],"title":"OrgProfileUpdateRequest"},"OrgRegisterRequest":{"type":"object","properties":{"identifier":{"type":"string","format":"email","description":"A malformed address otherwise reaches the mailer and 500s."},"identifier_type":{"type":"string","enum":["email","phone"]},"auth_method":{"type":"string","enum":["password","code"]},"password":{"type":["string","null"],"minLength":6},"name":{"type":["string","null"],"minLength":2,"maxLength":255}},"required":["identifier","identifier_type","auth_method"],"title":"OrgRegisterRequest"},"OrgResendRequest":{"type":"object","properties":{"identifier":{"type":"string"}},"required":["identifier"],"title":"OrgResendRequest"},"OrgVerifyRequest":{"type":"object","properties":{"identifier":{"type":"string"},"code":{"type":"string"}},"required":["identifier","code"],"title":"OrgVerifyRequest"},"OrganizationNotificationSettingResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"reminders_enabled":{"type":"boolean"},"email_reminder_enabled":{"type":"boolean"},"email_reminder_hours_before":{"type":"integer"},"telegram_reminder_enabled":{"type":"boolean"},"telegram_reminder_hours_before":{"type":"integer"},"database_reminder_enabled":{"type":"boolean"},"database_reminder_hours_before":{"type":"integer"},"staff_reminder_enabled":{"type":"boolean"},"staff_reminder_hours_before":{"type":"integer"},"telegram_enabled":{"type":"boolean"},"quiet_hours_enabled":{"type":"boolean"},"quiet_hours_start":{"type":"string"},"quiet_hours_end":{"type":"string"},"daily_digest_enabled":{"type":"boolean"},"daily_digest_time":{"type":"string"},"evening_summary_enabled":{"type":"boolean"},"evening_summary_time":{"type":"string"},"weekly_summary_enabled":{"type":"boolean"},"weekly_summary_weekday":{"type":"integer"},"weekly_summary_time":{"type":"string"},"max_instant_per_hour":{"type":"integer"},"coalesce_window_seconds":{"type":"integer"},"event_policy":{"type":"array","description":"Always the full map, with defaults filled in for events the\norganization has never touched, so the UI never has to guess.","items":{}},"updated_at":{"type":"string"}},"required":["id","organization_id","reminders_enabled","email_reminder_enabled","email_reminder_hours_before","telegram_reminder_enabled","telegram_reminder_hours_before","database_reminder_enabled","database_reminder_hours_before","staff_reminder_enabled","staff_reminder_hours_before","telegram_enabled","quiet_hours_enabled","quiet_hours_start","quiet_hours_end","daily_digest_enabled","daily_digest_time","evening_summary_enabled","evening_summary_time","weekly_summary_enabled","weekly_summary_weekday","weekly_summary_time","max_instant_per_hour","coalesce_window_seconds","event_policy","updated_at"],"title":"OrganizationNotificationSettingResource"},"OrganizationPaymentSettingResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"provider":{"type":"string"},"is_enabled":{"type":"boolean"},"has_credentials":{"type":"boolean"},"prepay_policy":{"type":"string"},"prepay_percentage":{"type":"integer"},"refund_on_cancellation":{"type":"boolean"},"refund_deadline_hours":{"type":["integer","null"]},"auto_remind_unpaid":{"type":"boolean"},"remind_after_minutes":{"type":"integer"},"success_url":{"type":["string","null"]},"cancel_url":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","organization_id","provider","is_enabled","has_credentials","prepay_policy","prepay_percentage","refund_on_cancellation","refund_deadline_hours","auto_remind_unpaid","remind_after_minutes","success_url","cancel_url","created_at","updated_at"],"title":"OrganizationPaymentSettingResource"},"OrganizationProfileResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]},"meta_keywords":{"type":["array","null"],"items":{"type":"string"}},"canonical_url":{"type":["string","null"]},"og_image":{"type":["string","null"]},"cover_image":{"type":["string","null"],"description":"Customization Fields"},"accent_color":{"type":["string","null"]},"featured_service_ids":{"type":"array","items":{"type":"integer"}},"featured_staff_ids":{"type":"array","items":{"type":"integer"}},"translations":{"type":"object","properties":{"about":{"type":"object","additionalProperties":{"type":"string"}},"meta_title":{"type":"object","additionalProperties":{"type":"string"}},"meta_description":{"type":"object","additionalProperties":{"type":"string"}},"faq":{"type":"array","items":{"type":"object","additionalProperties":{"type":"string"}}}},"required":["about","meta_title","meta_description","faq"]},"about":{"type":["string","null"]},"gallery":{"type":"array","items":{"type":"string"}},"orientation_photos":{"type":"array","items":{"type":"string"}},"map_photo":{"type":["string","null"]},"show_map_in_gallery":{"type":"boolean"},"social_links":{"type":"array","items":{"type":"string"}},"contact_links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"masked_phone":{"type":"string"}},"required":["platform","masked_phone"]}},"business_hours":{"type":"array","items":{"type":"string"}},"masked_phone":{"type":["string","null"]},"has_phone":{"type":"boolean"},"email":{"type":["string","null"]},"website":{"type":["string","null"]},"average_rating":{"type":"number"},"total_reviews":{"type":"integer"},"total_appointments":{"type":"integer"},"years_in_business":{"type":["integer","null"]},"amenities":{"type":"array","items":{"type":"string"}},"payment_methods":{"type":"array","items":{"type":"string"}},"nearby_landmarks":{"type":"array","items":{"type":"string"}},"services_detailed":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"tag":{"type":["string","null"]},"group":{"type":["string","null"]},"price":{"type":["string","null"]}},"required":["name","tag","group","price"]}},"floor_entrance":{"type":["string","null"]},"faq":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string"},"answer":{"type":"string"}},"required":["question","answer"]}},"services_offered":{"type":"array","items":{"type":"string"}},"price_range_min":{"type":["number","null"]},"price_range_max":{"type":["number","null"]},"next_available":{"type":["string","null"],"description":"Next upcoming availability window (from now, wrapping across days of week)"},"is_published":{"type":"boolean","description":"Status"},"is_featured":{"type":"boolean"},"is_bookable":{"type":"boolean"},"published_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"distance":{"type":"string","description":"Distance from user (km), included when lat/lng query params are provided"},"organization":{"type":"object","description":"Organization data (included when eager-loaded, e.g. in search results)","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"specialty":{"type":["string","null"]},"district":{"type":["string","null"],"description":"Scraped from 2GIS as a Russian adm_div string\n(\"Юнусабадский район\"), so it goes through the shared\ndirectory dictionary like every other imported term —\notherwise the English and Uzbek cards read\n\"Tashkent, Юнусабадский район\"."},"city":{"type":"string"},"city_slug":{"type":["string","null"],"description":"The city SEGMENT of the venue URL (ODI-182), not the\ndisplay name. `city` above is translated and free-text;\nthis is `cities.slug`, identical in every locale, and is\nwhat `/{locale}/{city}/{category}/{venue}` is built from.\nNull for the handful of orgs with no resolved `city_id` —\nthey fall back to the flat `/{venue}` form."},"state":{"type":"string"},"logo":{"type":["string","null"]},"address":{"type":["string","null"]},"is_claimed":{"type":"boolean"},"is_verified":{"type":"boolean"},"latitude":{"type":["number","null"],"description":"Latitude of the main branch"},"longitude":{"type":["number","null"],"description":"Longitude of the main branch"},"primary_category":{"type":["object","null"],"properties":{"slug":{"type":"string"},"locale_slug":{"type":"string"},"name":{"type":"string"},"icon":{"type":["string","null"]},"illustration":{"type":["string","null"]}},"required":["slug","locale_slug","name","icon","illustration"]}},"required":["id","business_name","slug","specialty","district","city","city_slug","state","logo","address","is_claimed","is_verified","latitude","longitude"]}},"required":["id","organization_id","meta_title","meta_description","meta_keywords","canonical_url","og_image","cover_image","accent_color","featured_service_ids","featured_staff_ids","translations","about","gallery","orientation_photos","map_photo","show_map_in_gallery","social_links","contact_links","business_hours","masked_phone","has_phone","email","website","average_rating","total_reviews","total_appointments","years_in_business","amenities","payment_methods","nearby_landmarks","services_detailed","floor_entrance","faq","services_offered","price_range_min","price_range_max","next_available","is_published","is_featured","is_bookable","published_at","created_at","updated_at"],"title":"OrganizationProfileResource"},"OrganizationPublicResource":{"type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"string"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"specialty":{"type":["string","null"]},"description":{"type":["string","null"]},"logo":{"type":"string"},"address":{"type":["string","null"]},"district":{"type":["string","null"],"description":"Russian 2GIS adm_div, resolved through the directory dictionary."},"city":{"type":"string"},"state":{"type":"string"},"country":{"type":"string"},"postal_code":{"type":"string"},"timezone":{"type":"string"},"default_currency":{"type":"string"}},"required":["id","business_name","slug","specialty","description","logo","address","district","city","state","country","postal_code","timezone","default_currency"]},"profile":{"type":"object","properties":{"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]},"about":{"type":["string","null"]},"gallery":{"type":"string"},"social_links":{"type":"string"},"business_hours":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"average_rating":{"type":"string"},"total_reviews":{"type":"string"},"total_appointments":{"type":"string"},"years_in_business":{"type":"string"},"faq":{"type":"string"},"price_range_min":{"type":"string"},"price_range_max":{"type":"string"},"is_featured":{"type":"string"},"is_bookable":{"type":"boolean"}},"required":["meta_title","meta_description","about","gallery","social_links","business_hours","phone","email","website","average_rating","total_reviews","total_appointments","years_in_business","faq","price_range_min","price_range_max","is_featured","is_bookable"]},"services":{"type":"string"},"staff":{"type":"string"},"branches":{"type":"string"},"reviews":{"type":"string"},"categories":{"type":"string"},"announcements":{"type":"string"},"booking_settings":{"type":"string"},"structured_data":{"type":"string"}},"required":["organization","booking_settings"],"title":"OrganizationPublicResource"},"OrganizationResource":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"specialty":{"type":["string","null"]},"description":{"type":["string","null"]},"translations":{"type":"object","properties":{"business_name":{"type":"object","additionalProperties":{"type":"string"}},"specialty":{"type":"object","additionalProperties":{"type":"string"}},"description":{"type":"object","additionalProperties":{"type":"string"}},"address":{"type":"object","additionalProperties":{"type":"string"}}},"required":["business_name","specialty","description","address"]},"address":{"type":["string","null"]},"district":{"type":["string","null"]},"city":{"type":"string"},"canonical_path":{"type":"string","description":"Where this organization's public page lives, WITHOUT the locale\nprefix: `/tashkent/barber/britva` (ODI-182). The dashboard shows this URL back to the owner — the profile\nform's copy button, the share dialog's QR code, the onboarding\n\"your page is live\" step. All three used to concatenate\n`{clientBase}/{slug}`, which stopped resolving when venue pages\nmoved under city and category: the bare slug 404s rather than\nredirecting, so the owner was handed a dead link to their own\nbusiness.\n\nFalls back to `/{slug}` when the org has no resolved city or no\ncategory — that form does not resolve either, but a page in that\nstate is not publishable anyway, and the fallback keeps the\nbreakage at the link rather than emitting `//britva`."},"short_code":{"type":["string","null"],"description":"Permanent share code — `bronjoy.com/s/{code}`. Never changes, so\nanything printed with it (the QR poster, a sticker) keeps working\nafter a rename or a re-mint. See `ShortCode`."},"state":{"type":"string"},"country":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"timezone":{"type":"string"},"default_currency":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"logo":{"type":["string","null"]},"invite_code":{"type":["string","null"]},"referral_code":{"type":["string","null"]},"referral_link":{"type":"string"},"allow_join_requests":{"type":"boolean"},"is_active":{"type":"string"},"is_verified":{"type":"boolean"},"verified_at":{"type":"string"},"telegram_bot_connected":{"type":"boolean"},"telegram_bot_username":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"branches":{"type":"array","items":{"$ref":"#/components/schemas/Branch"}},"services":{"type":"array","items":{"$ref":"#/components/schemas/Service"}},"staff":{"type":"array","items":{"$ref":"#/components/schemas/Staff"}}},"required":["id","business_name","slug","specialty","description","translations","address","district","city","canonical_path","short_code","state","country","postal_code","timezone","default_currency","phone","email","website","logo","invite_code","referral_code","referral_link","allow_join_requests","is_active","is_verified","verified_at","telegram_bot_connected","telegram_bot_username","created_at","updated_at"],"title":"OrganizationResource"},"PartnerCommissionResource":{"type":"object","properties":{"id":{"type":"integer"},"amount":{"type":"number"},"base_amount":{"type":"number"},"rate":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string"},"status_label":{"type":"string","enum":["Pending","Approved","Paid","Reversed"]},"period":{"type":["string","null"]},"earned_at":{"type":"string"},"created_at":{"type":"string"},"business":{"type":"object","properties":{"id":{"type":"string"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":"string"}},"required":["id","business_name","slug","logo"]}},"required":["id","amount","base_amount","rate","currency","status","status_label","period","earned_at","created_at","business"],"title":"PartnerCommissionResource"},"PartnerPayoutMethodResource":{"type":"object","properties":{"id":{"type":"integer"},"type":{"type":"string"},"brand":{"type":["string","null"]},"last4":{"type":["string","null"]},"holder_name":{"type":["string","null"]},"is_default":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","type","brand","last4","holder_name","is_default","created_at"],"title":"PartnerPayoutMethodResource"},"PartnerPayoutResource":{"type":"object","properties":{"id":{"type":"integer"},"amount":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string"},"status_label":{"type":"string","enum":["Requested","Processing","Paid","Rejected"]},"reference":{"type":["string","null"]},"processed_at":{"type":"string"},"created_at":{"type":"string"}},"required":["id","amount","currency","status","status_label","reference","processed_at","created_at"],"title":"PartnerPayoutResource"},"PaymentTransactionResource":{"type":"object","properties":{"id":{"type":"integer"},"appointment_id":{"type":"integer"},"state":{"type":"string"},"provider":{"type":"string"},"method":{"type":"string"},"amount":{"type":"integer","description":"Integer amount in the currency's MINOR units (tiyin for UZS: 150 000 сум = 15000000).\nDivide by 10^currency_scale for the major amount."},"currency":{"type":"string"},"currency_scale":{"type":"integer","description":"ISO 4217 minor-unit digits of `currency` (UZS = 2, JPY = 0)."},"provider_transaction_id":{"type":["string","null"]},"error_code":{"type":["string","null"]},"error_note":{"type":["string","null"]},"cancel_reason":{"type":["string","null"]},"perform_time":{"type":"string"},"cancel_time":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"appointment":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"start_time":{"type":"string"},"status":{"type":"string"},"client":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}},"required":["id","name","email","phone"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"service":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]}},"required":["id","title","start_time","status","client","staff","service"]}},"required":["id","appointment_id","state","provider","method","amount","currency","currency_scale","provider_transaction_id","error_code","error_note","cancel_reason","perform_time","cancel_time","created_at","updated_at"],"title":"PaymentTransactionResource"},"PrepayPolicy":{"type":"string","enum":["none","partial","full"],"title":"PrepayPolicy"},"RecordVenueEventRequest":{"type":"object","properties":{"type":{"type":"string","description":"Phone reveals are not accepted here — the reveal endpoint counts them itself.","enum":["view","messenger","directions"]}},"required":["type"],"title":"RecordVenueEventRequest"},"ReferralPartnerResource":{"type":"object","properties":{"code":{"type":"string"},"link":{"type":"string"},"status":{"type":"string"},"commission_rate":{"type":"number"},"currency":{"type":"string"},"min_payout":{"type":"integer"},"stats":{"type":"object","properties":{"total_earned":{"type":"number"},"pending":{"type":"number"},"available_balance":{"type":"number"},"paid_out":{"type":"number"},"referred_businesses":{"type":"integer"},"converted_businesses":{"type":"integer"}},"required":["total_earned","pending","available_balance","paid_out","referred_businesses","converted_businesses"]}},"required":["code","link","status","commission_rate","currency","min_payout","stats"],"title":"ReferralPartnerResource"},"ReferralResource":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string"},"status_label":{"type":"string","enum":["Pending","Completed","Expired"]},"reward_days":{"type":"integer"},"rewarded_at":{"type":"string"},"created_at":{"type":"string"},"referrer":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]}},"required":["id","business_name","slug","logo"]},"referred":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]}},"required":["id","business_name","slug","logo"]}},"required":["id","status","status_label","reward_days","rewarded_at","created_at","referrer","referred"],"title":"ReferralResource"},"ReferredBusinessResource":{"type":"object","properties":{"id":{"type":"integer"},"business_name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]},"city":{"type":["string","null"]},"status":{"type":"string","description":"\"active\" once the business starts paying (and earning you commission),\notherwise \"pending\" (registered but not yet subscribed).","enum":["active","pending"]},"earned":{"type":"number"},"attributed_at":{"type":"string"}},"required":["id","business_name","slug","logo","city","status","earned","attributed_at"],"title":"ReferredBusinessResource"},"RejectJoinRequest":{"type":"object","properties":{"rejection_reason":{"type":["string","null"],"maxLength":500}},"title":"RejectJoinRequest"},"ReplyReviewRequest":{"type":"object","properties":{"reply":{"type":"string","maxLength":1000}},"required":["reply"],"title":"ReplyReviewRequest"},"ReportReviewRequest":{"type":"object","properties":{"reason":{"type":"string","minLength":10,"maxLength":1000}},"required":["reason"],"title":"ReportReviewRequest"},"RequestBookingCodeRequest":{"type":"object","description":"Step one of a guest booking: ask for a confirmation code.\n\nDeliberately takes only the contact, not the slot — nothing is reserved by\nasking for a code, so there is no state to hold or expire between the two\ncalls.","properties":{"email":{"type":["string","null"],"format":"email","maxLength":255},"phone":{"type":["string","null"],"maxLength":50}},"title":"RequestBookingCodeRequest"},"RequestEmailChangeRequest":{"type":"object","properties":{"new_email":{"type":"string","format":"email"}},"required":["new_email"],"title":"RequestEmailChangeRequest"},"RequestEmailRequest":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"],"title":"RequestEmailRequest"},"RequestPartnerPayoutRequest":{"type":"object","properties":{"amount":{"type":["number","null"],"description":"Omit to withdraw the full available balance.","minimum":0},"payout_method_id":{"type":["integer","null"]}},"title":"RequestPartnerPayoutRequest"},"RequestPhoneChangeRequest":{"type":"object","properties":{"new_phone":{"type":"string"}},"required":["new_phone"],"title":"RequestPhoneChangeRequest"},"RequestPhoneRequest":{"type":"object","properties":{"phone":{"type":"string"}},"required":["phone"],"title":"RequestPhoneRequest"},"RescheduleAppointmentRequest":{"type":"object","properties":{"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"}},"required":["start_time","end_time"],"title":"RescheduleAppointmentRequest"},"ReviewResource":{"type":"object","properties":{"id":{"type":"integer"},"rating":{"type":"integer"},"comment":{"type":["string","null"]},"reply":{"type":["string","null"]},"is_public":{"type":"boolean"},"replied_at":{"type":"string"},"is_reported":{"type":"boolean"},"reported_at":{"type":"string"},"report_reason":{"type":["string","null"]},"report_status":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":["string","null"]}},"required":["id","name","slug","logo"]},"appointment":{"type":"object","properties":{"id":{"type":"integer"},"date":{"type":"string"},"service":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]}},"required":["id","date","service","staff"]},"client":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"replied_by":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"reported_by":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]}},"required":["id","rating","comment","reply","is_public","replied_at","is_reported","reported_at","report_status","created_at","updated_at"],"title":"ReviewResource"},"SearchInviteCodeRequest":{"type":"object","properties":{"invite_code":{"type":"string","minLength":4,"maxLength":20}},"required":["invite_code"],"title":"SearchInviteCodeRequest"},"SendMessageRequest":{"type":"object","properties":{"content":{"type":"string","maxLength":2000}},"required":["content"],"title":"SendMessageRequest"},"Service":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"category_id":{"type":["integer","null"]},"name":{"type":"array","items":{}},"description":{"type":["array","null"],"items":{}},"duration":{"type":"integer"},"buffer_before":{"type":"integer"},"buffer_after":{"type":"integer"},"price":{"type":"string"},"currency":{"type":"string"},"is_active":{"type":"boolean"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"deleted_at":{"type":["string","null"],"format":"date-time"},"prepay_policy":{"anyOf":[{"$ref":"#/components/schemas/PrepayPolicy"},{"type":"null"}]},"prepay_percentage":{"type":["integer","null"]},"price_from":{"type":"boolean"},"source":{"$ref":"#/components/schemas/ServiceSource"},"source_tag":{"type":["string","null"]}},"required":["id","organization_id","category_id","name","description","duration","buffer_before","buffer_after","price","currency","is_active","created_at","updated_at","deleted_at","prepay_policy","prepay_percentage","price_from","source","source_tag"],"title":"Service"},"ServiceResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"category_id":{"type":["integer","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"translations":{"type":"object","properties":{"name":{"type":"object","additionalProperties":{"type":"string"}},"description":{"type":"object","additionalProperties":{"type":"string"}}},"required":["name","description"]},"duration":{"type":"integer"},"buffer_before":{"type":"integer"},"buffer_after":{"type":"integer"},"price":{"type":"number"},"price_from":{"type":"boolean","description":"Whether `price` is a starting price (\"от 40 000 сум\") rather than the price."},"currency":{"type":"string"},"prepay_policy":{"type":"string"},"prepay_percentage":{"type":["integer","null"]},"is_active":{"type":"boolean"},"source":{"type":"string","description":"Where the row came from: `owner` if a person entered it, `scraped` if it was materialised from 2GIS directory data."},"created_at":{"type":"string"},"updated_at":{"type":"string"},"deleted_at":{"type":"string"},"category":{"$ref":"#/components/schemas/Category"},"staff":{"type":"array","items":{"$ref":"#/components/schemas/Staff"}}},"required":["id","organization_id","category_id","name","description","translations","duration","buffer_before","buffer_after","price","price_from","currency","prepay_policy","prepay_percentage","is_active","source","created_at","updated_at","deleted_at"],"title":"ServiceResource"},"ServiceSource":{"type":"string","description":"Where a service row came from. Scraped rows are materialised from `organization_profiles.services_detailed` (2GIS attributes) and may be rewritten by a later import; owner rows are whatever a real person typed and are never touched by the importer.\n","enum":["owner","scraped"],"title":"ServiceSource"},"SettingsResource":{"type":"object","properties":{"booking_min_lead_hours":{"type":"integer"},"booking_max_lead_days":{"type":"integer"},"waitlist_enabled":{"type":"string"},"waitlist_auto_promote":{"type":"string"},"waitlist_promotion_window_hours":{"type":"integer"},"cancellation_min_hours":{"type":"integer"},"reschedule_min_hours":{"type":"integer"}},"required":["booking_min_lead_hours","booking_max_lead_days","waitlist_enabled","waitlist_auto_promote","waitlist_promotion_window_hours","cancellation_min_hours","reschedule_min_hours"],"title":"SettingsResource"},"SitemapUrlResource":{"type":"object","properties":{"loc":{"type":"string"},"lastmod":{"type":"string"},"changefreq":{"type":"string"},"priority":{"type":"number"}},"required":["loc","lastmod","changefreq","priority"],"title":"SitemapUrlResource"},"SlotResource":{"type":"object","properties":{"start_time":{"type":"string"},"end_time":{"type":"string"},"staff_id":{"type":"string"},"staff_name":{"type":"string"},"duration":{"type":"string"},"is_available":{"type":"string"}},"required":["start_time","end_time","staff_id","staff_name","duration","is_available"],"title":"SlotResource"},"Staff":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"user_id":{"type":["integer","null"]},"branch_id":{"type":["integer","null"]},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"is_active":{"type":"boolean"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"deleted_at":{"type":["string","null"],"format":"date-time"},"telegram_user_id":{"type":["string","null"]},"display_name":{"type":["array","null"],"items":{}},"position":{"type":["array","null"],"items":{}},"bio":{"type":["array","null"],"items":{}},"avatar":{"type":["string","null"]},"slug":{"type":["string","null"]},"is_profile_public":{"type":"boolean"},"meta_title":{"type":["array","null"],"items":{}},"meta_description":{"type":["array","null"],"items":{}},"ical_feed_token":{"type":["string","null"]},"onboarding_completed_at":{"type":["string","null"],"format":"date-time"},"is_verified":{"type":"boolean"},"verified_at":{"type":["string","null"],"format":"date-time"}},"required":["id","organization_id","user_id","branch_id","name","email","phone","is_active","created_at","updated_at","deleted_at","telegram_user_id","display_name","position","bio","avatar","slug","is_profile_public","meta_title","meta_description","ical_feed_token","onboarding_completed_at","is_verified","verified_at"],"title":"Staff"},"StaffInviteRequest":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","maxLength":255},"organization_id":{"type":"integer"},"roles":{"type":"array","items":{"type":"string","enum":["owner","manager","service_provider","receptionist"]}}},"required":["email","name","organization_id","roles"],"title":"StaffInviteRequest"},"StaffJoinRequestResource":{"type":"object","properties":{"id":{"type":"integer"},"user_id":{"type":"integer"},"organization_id":{"type":"integer"},"status":{"type":"string"},"message":{"type":["string","null"]},"rejection_reason":{"type":["string","null"]},"invite_code":{"type":["string","null"]},"processed_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"user":{"$ref":"#/components/schemas/UserResource"},"organization":{"$ref":"#/components/schemas/OrganizationResource"}},"required":["id","user_id","organization_id","status","message","rejection_reason","invite_code","processed_at","created_at","updated_at"],"title":"StaffJoinRequestResource"},"StaffNotificationPreferenceResource":{"type":"object","properties":{"id":{"type":"integer"},"staff_id":{"type":"integer"},"telegram_linked":{"type":"boolean"},"telegram_blocked":{"type":"boolean"},"telegram_muted":{"type":"boolean"},"muted_until":{"type":"string"},"is_silenced":{"type":"boolean"},"is_owner":{"type":"boolean"},"daily_digest_enabled":{"type":["boolean","null"]},"daily_digest_time":{"type":["string","null"]},"quiet_hours_enabled":{"type":["boolean","null"]},"quiet_hours_start":{"type":["string","null"]},"quiet_hours_end":{"type":["string","null"]},"event_overrides":{"type":"string","description":"Cast to object so an empty override map serialises as {} rather\nthan [], which would not match the declared record type."},"effective_policy":{"type":"string","description":"What this person will actually receive, after the org policy caps\ntheir overrides."},"organization_policy":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","staff_id","telegram_linked","telegram_blocked","telegram_muted","muted_until","is_silenced","is_owner","daily_digest_enabled","daily_digest_time","quiet_hours_enabled","quiet_hours_start","quiet_hours_end","event_overrides","effective_policy","organization_policy","updated_at"],"title":"StaffNotificationPreferenceResource"},"StaffOrganizationResource":{"type":"object","properties":{"id":{"type":"string"},"staff_id":{"type":"string"},"name":{"type":["string","null"]},"slug":{"type":"string"},"logo":{"type":"string"},"role":{"type":"string"},"onboarding_completed_at":{"type":"string"},"onboarding_state":{"type":"string"}},"required":["id","staff_id","name","slug","logo","role","onboarding_completed_at","onboarding_state"],"title":"StaffOrganizationResource"},"StaffResource":{"type":"object","properties":{"id":{"type":"integer"},"organization_id":{"type":"integer"},"user_id":{"type":["integer","null"]},"branch_id":{"type":["integer","null"]},"name":{"type":"string"},"display_name":{"type":["string","null"]},"slug":{"type":["string","null"]},"position":{"type":["string","null"]},"bio":{"type":["string","null"]},"avatar":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_verified":{"type":"boolean"},"verified_at":{"type":"string"},"is_profile_public":{"type":"boolean"},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]},"translations":{"type":"object","properties":{"display_name":{"type":"object","additionalProperties":{"type":"string"}},"position":{"type":"object","additionalProperties":{"type":"string"}},"bio":{"type":"object","additionalProperties":{"type":"string"}},"meta_title":{"type":"object","additionalProperties":{"type":"string"}},"meta_description":{"type":"object","additionalProperties":{"type":"string"}}},"required":["display_name","position","bio","meta_title","meta_description"]},"roles":{"type":"string"},"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"duration":{"type":"integer"}},"required":["id","name","duration"]}},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}},"required":["id","organization_id","user_id","branch_id","name","display_name","slug","position","bio","avatar","email","phone","is_active","is_verified","verified_at","is_profile_public","meta_title","meta_description","translations","roles","services","created_at","updated_at"],"title":"StaffResource"},"StartOrGetConversationRequest":{"type":"object","properties":{"organization_slug":{"type":"string"}},"required":["organization_slug"],"title":"StartOrGetConversationRequest"},"StoreAppointmentRequest":{"type":"object","properties":{"client_id":{"type":"integer"},"service_id":{"type":"integer"},"staff_id":{"type":["integer","null"]},"branch_id":{"type":["integer","null"]},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"notes":{"type":["string","null"],"maxLength":500},"status":{"type":["string","null"],"enum":["pending","confirmed"]},"payment_status":{"type":["string","null"],"enum":["unpaid","paid"]}},"required":["client_id","service_id","start_time","end_time"],"title":"StoreAppointmentRequest"},"StoreClaimRequest":{"type":"object","properties":{"organization_slug":{"type":"string"},"applicant_role":{"type":"string","enum":["owner","manager","employee","representative","other"]},"applicant_name":{"type":"string","maxLength":255},"applicant_phone":{"type":["string","null"],"description":"We promise a call to anyone who has not sent a document yet, so without\none we need a number to call. It is contact info, never proof of ownership.","maxLength":50},"applicant_email":{"type":["string","null"],"format":"email","maxLength":255},"message":{"type":["string","null"],"maxLength":5000},"tracking_token":{"type":["string","null"],"description":"The flyer or promoter code from the `bj_tk` cookie. A malformed one is ignored.","maxLength":255},"documents":{"type":["array","null"],"description":"Optional at submission: the claim is recorded and a person follows up.\nApproval still needs a document or a personal check, see\nClaimReviewService::approve().","items":{"type":"object","properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","maxLength":10240},"kind":{"type":"string","enum":["registration_cert","tax_cert","license","lease","utility_bill","other"]}},"required":["file","kind"]},"maxItems":5}},"required":["organization_slug","applicant_role","applicant_name"],"title":"StoreClaimRequest"},"StoreClientNoteRequest":{"type":"object","properties":{"content":{"type":"string","maxLength":2000}},"required":["content"],"title":"StoreClientNoteRequest"},"StoreDeviceTokenRequest":{"type":"object","properties":{"token":{"type":"string","maxLength":512},"platform":{"type":"string","enum":["ios","android","web"]},"locale":{"type":["string","null"],"enum":["en","uz","ru"]}},"required":["token","platform"],"title":"StoreDeviceTokenRequest"},"StoreJoinRequest":{"type":"object","properties":{"organization_id":{"type":"integer"},"message":{"type":["string","null"],"maxLength":500},"invite_code":{"type":["string","null"]}},"required":["organization_id"],"title":"StoreJoinRequest"},"StorePartnerPayoutMethodRequest":{"type":"object","properties":{"card_number":{"type":"string","description":"Card number, spaces allowed; 12–19 digits covers UzCard/Humo/Visa/Mastercard."},"holder_name":{"type":["string","null"],"maxLength":255},"is_default":{"type":["boolean","null"]}},"required":["card_number"],"title":"StorePartnerPayoutMethodRequest"},"StoreScheduleEntryRequest":{"type":"object","properties":{"is_recurring":{"type":"boolean"},"date":{"type":"string","format":"date"},"start_time":{"type":"string"},"end_time":{"type":"string"},"staff_id":{"type":["integer","null"]},"service_id":{"type":["integer","null"]},"is_available":{"type":"boolean"},"reason":{"type":["string","null"],"maxLength":255},"days_of_week":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}}},"required":["is_recurring","start_time","end_time"],"title":"StoreScheduleEntryRequest"},"StoreSupportTicketMessageRequest":{"type":"object","properties":{"message":{"type":"string","maxLength":5000}},"required":["message"],"title":"StoreSupportTicketMessageRequest"},"StoreSupportTicketRequest":{"type":"object","properties":{"subject":{"type":"string","maxLength":255},"category":{"type":"string","enum":["technical","billing","account","booking","feature_request","other"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"message":{"type":"string","maxLength":5000}},"required":["subject","category","message"],"title":"StoreSupportTicketRequest"},"StoreWaitlistEntryRequest":{"type":"object","properties":{"client_id":{"type":"integer"},"service_id":{"type":"integer"},"staff_id":{"type":["integer","null"]},"branch_id":{"type":["integer","null"]},"preferred_date":{"type":"string","format":"date-time"},"preferred_time_slot":{"type":["string","null"],"enum":["morning","afternoon","evening"]},"notes":{"type":["string","null"],"maxLength":500}},"required":["client_id","service_id","preferred_date"],"title":"StoreWaitlistEntryRequest"},"SubmitBookingRequestRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"phone":{"type":"string","description":"+998 and nine digits; the nine local digits alone are accepted too.","maxLength":32},"service":{"type":["string","null"],"maxLength":120},"preferred_time":{"type":["string","null"],"description":"Free text in the visitor's words, e.g. \"завтра после 18:00\".","maxLength":80},"comment":{"type":["string","null"],"maxLength":300},"cf-turnstile-response":{"type":["string","null"],"description":"The Turnstile token, checked by the `turnstile` middleware (dormant without keys)."}},"required":["name","phone"],"title":"SubmitBookingRequestRequest"},"SubscriptionResource":{"type":"object","properties":{"id":{"type":"integer"},"tier":{"type":"string"},"tier_label":{"type":"string","enum":["Spark","Avtopilot"]},"is_paid":{"type":"boolean"},"is_active":{"type":"boolean"},"cancelled":{"type":"boolean"},"on_grace_period":{"type":"boolean"},"ends_at":{"type":"string"},"period_start":{"type":"string"},"period_end":{"type":"string"},"extra_branches":{"type":"integer"},"billing_provider":{"type":"string"},"self_serve_checkout":{"type":"boolean","description":"False while there is no merchant account to collect with: the UI\nswaps every checkout button for a \"contact us\" CTA and the\nmatching endpoints answer 409."},"contact_url":{"type":"string"},"plan":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"string"},"currency":{"type":"string"},"features":{"type":"string"},"coming_soon":{"type":"string"},"limits":{"type":"string"},"branding":{"type":"string"}},"required":["name","price","currency","features","coming_soon","limits","branding"]},"usage":{"type":"object","properties":{"staff_count":{"type":"string"},"staff_limit":{"type":"string"},"branch_count":{"type":"string"},"branch_limit":{"type":"integer"}},"required":["staff_count","staff_limit","branch_count","branch_limit"]},"ai_usage":{"type":"object","properties":{"tokens_used_today":{"type":"string"},"daily_token_limit":{"type":"string","description":"null = unlimited, 0 = none included (credits only)"},"per_user_daily_token_limit":{"type":"string","description":"null = no per-user sub-cap configured"},"credit_balance":{"type":"string","description":"Purchased overflow tokens that survive the daily reset."},"credit_pack":{"type":"object","properties":{"tokens":{"type":"integer"},"price":{"type":"integer"},"currency":{"type":"string"}},"required":["tokens","price","currency"]}},"required":["tokens_used_today","daily_token_limit","per_user_daily_token_limit","credit_balance","credit_pack"]},"branch_addon_price":{"type":"string"},"is_referral_reward":{"type":"boolean"},"referral_reward_ends_at":{"type":["string","null"]}},"required":["id","tier","tier_label","is_paid","is_active","cancelled","on_grace_period","ends_at","period_start","period_end","extra_branches","billing_provider","self_serve_checkout","contact_url","plan","usage","ai_usage","branch_addon_price","is_referral_reward","referral_reward_ends_at"],"title":"SubscriptionResource"},"SupportTicketMessageResource":{"type":"object","properties":{"id":{"type":"integer"},"ticket_id":{"type":["integer","null"]},"sender_type":{"type":"string","enum":["org","ai","system","support"]},"sender_name":{"type":"string","enum":["Bronjoy Support","Bronjoy Assistant","System","You"]},"body":{"type":"string"},"is_read":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","ticket_id","sender_type","sender_name","body","is_read","created_at"],"title":"SupportTicketMessageResource"},"SupportTicketResource":{"type":"object","properties":{"id":{"type":"integer"},"reference":{"type":"string"},"subject":{"type":"string"},"category":{"type":"string"},"category_label":{"type":"string"},"priority":{"type":"string"},"priority_label":{"type":"string"},"status":{"type":"string"},"status_label":{"type":"string"},"last_sender":{"type":["string","null"]},"last_message_preview":{"type":["string","null"]},"unread_count":{"type":"integer"},"messages_count":{"type":"integer"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicketMessageResource"}},"last_message_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","reference","subject","category","category_label","priority","priority_label","status","status_label","last_sender","last_message_preview","unread_count","last_message_at","created_at","updated_at"],"title":"SupportTicketResource"},"SyncFavoritesRequest":{"type":"object","properties":{"slugs":{"type":"array","items":{"type":"string","maxLength":255},"maxItems":50}},"required":["slugs"],"title":"SyncFavoritesRequest"},"TelegramAuthRequest":{"type":"object","properties":{"initData":{"type":"string"},"phone":{"type":["string","null"]},"organization_id":{"type":["integer","null"]},"organization_slug":{"type":["string","null"]},"create":{"type":["boolean","null"],"description":"Login-only mode: when false, staffAuth resolves an existing\naccount but never creates one (used by the TMA's silent on-open\ncheck so opening the app can't fabricate a ghost user)."}},"required":["initData"],"title":"TelegramAuthRequest"},"TelegramStaffAuthResource":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"needs_onboarding":{"type":"string"},"user":{"$ref":"#/components/schemas/UserResource"},"organizations":{"type":"array","items":{"$ref":"#/components/schemas/StaffOrganizationResource"}},"telegram":{"type":"object","properties":{"username":{"type":"string"},"is_premium":{"type":"string"}},"required":["username","is_premium"]}},"required":["access_token","token_type","needs_onboarding","user","organizations","telegram"],"title":"TelegramStaffAuthResource"},"ToggleFavoriteRequest":{"type":"object","properties":{"organization_id":{"type":"integer"}},"required":["organization_id"],"title":"ToggleFavoriteRequest"},"TranslateRequest":{"type":"object","properties":{"source_locale":{"type":"string","enum":["en","uz","ru"]},"text":{"type":"string","maxLength":50000},"target_locales":{"type":"array","items":{"type":"string","enum":["en","uz","ru"]},"minItems":1}},"required":["source_locale","text","target_locales"],"title":"TranslateRequest"},"UpdateAnnouncementRequest":{"type":"object","properties":{"type":{"type":"string","enum":["info","warning","critical"]},"target":{"type":"string","enum":["all_clients","recent_clients"]},"is_active":{"type":"boolean"},"publish_at":{"type":["string","null"],"format":"date-time"},"expire_at":{"type":["string","null"],"format":"date-time"},"title":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"content":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":5000},"uz":{"type":["string","null"],"maxLength":5000},"ru":{"type":["string","null"],"maxLength":5000}}}},"title":"UpdateAnnouncementRequest"},"UpdateAppointmentRequest":{"type":"object","properties":{"client_id":{"type":"integer"},"service_id":{"type":"integer"},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"staff_id":{"type":"integer"},"notes":{"type":"string","maxLength":500},"status":{"type":"string","enum":["pending","confirmed","completed","cancelled","no_show"]}},"title":"UpdateAppointmentRequest"},"UpdateBranchRequest":{"type":"object","properties":{"phone":{"type":["string","null"],"maxLength":20},"district":{"type":["string","null"],"maxLength":255},"city":{"type":["string","null"],"maxLength":255},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"is_main":{"type":"boolean"},"name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"address":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":500},"uz":{"type":["string","null"],"maxLength":500},"ru":{"type":["string","null"],"maxLength":500}}}},"title":"UpdateBranchRequest"},"UpdateClientNotificationSettingsRequest":{"type":"object","properties":{"email":{"type":"boolean"},"sms":{"type":"boolean"},"telegram":{"type":"boolean"},"database":{"type":"boolean"}},"title":"UpdateClientNotificationSettingsRequest"},"UpdateClientRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"email":{"type":["string","null"],"format":"email","maxLength":255},"phone":{"type":["string","null"],"maxLength":20},"address":{"type":"string","maxLength":500},"notes":{"type":["string","null"],"maxLength":1000}},"title":"UpdateClientRequest"},"UpdateNotificationSettingRequest":{"type":"object","properties":{"reminders_enabled":{"type":"boolean"},"email_reminder_enabled":{"type":"boolean"},"email_reminder_hours_before":{"type":"integer","minimum":1,"maximum":168},"telegram_reminder_enabled":{"type":"boolean","description":"max 1 week"},"telegram_reminder_hours_before":{"type":"integer","minimum":1,"maximum":72},"database_reminder_enabled":{"type":"boolean"},"database_reminder_hours_before":{"type":"integer","minimum":1,"maximum":168},"staff_reminder_enabled":{"type":"boolean"},"staff_reminder_hours_before":{"type":"integer","minimum":1,"maximum":72},"telegram_enabled":{"type":"boolean","description":"Provider Telegram bot policy."},"quiet_hours_enabled":{"type":"boolean"},"quiet_hours_start":{"type":"string"},"quiet_hours_end":{"type":"string"},"daily_digest_enabled":{"type":"boolean"},"daily_digest_time":{"type":"string"},"evening_summary_enabled":{"type":"boolean"},"evening_summary_time":{"type":"string"},"weekly_summary_enabled":{"type":"boolean"},"weekly_summary_weekday":{"type":"integer","minimum":1,"maximum":7},"weekly_summary_time":{"type":"string"},"max_instant_per_hour":{"type":"integer","minimum":0,"maximum":120},"coalesce_window_seconds":{"type":"integer","minimum":0,"maximum":900},"event_policy":{"type":"array","description":"Only known event keys, only known delivery modes.","items":{"type":"string","enum":["instant","digest","off"]}}},"title":"UpdateNotificationSettingRequest"},"UpdateOnboardingStateRequest":{"type":"object","properties":{"current_step":{"type":"integer","minimum":1,"maximum":20},"completed_steps":{"type":["array","null"],"items":{"type":"integer","minimum":1,"maximum":20}}},"required":["current_step"],"title":"UpdateOnboardingStateRequest"},"UpdateOrganizationProfileRequest":{"type":"object","properties":{"canonical_url":{"type":["string","null"],"format":"uri","maxLength":500},"og_image":{"type":["string","null"],"format":"uri","maxLength":500},"cover_image":{"type":["string","null"],"format":"uri","description":"Customization fields","maxLength":500},"accent_color":{"type":["string","null"],"maxLength":7},"business_hours":{"type":["array","null"],"items":{"type":"string"}},"faq":{"type":["array","null"],"items":{"type":"string"},"maxItems":20},"phone":{"type":["string","null"],"description":"Contact fields","maxLength":50},"email":{"type":["string","null"],"format":"email","maxLength":255},"website":{"type":["string","null"],"format":"uri","maxLength":500},"years_in_business":{"type":["integer","null"],"description":"Business info","minimum":0,"maximum":200},"services_offered":{"type":["array","null"],"items":{"type":"string"}},"price_range_min":{"type":["number","null"],"minimum":0,"maximum":999999},"price_range_max":{"type":["number","null"],"minimum":0,"maximum":999999},"show_map_in_gallery":{"type":["boolean","null"],"description":"Map"},"is_published":{"type":["boolean","null"],"description":"Status"},"is_featured":{"type":["boolean","null"]},"meta_title":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":70},"uz":{"type":["string","null"],"maxLength":70},"ru":{"type":["string","null"],"maxLength":70}}},"meta_description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":320},"uz":{"type":["string","null"],"maxLength":320},"ru":{"type":["string","null"],"maxLength":320}}},"meta_keywords":{"type":["array","null"],"items":{"type":"string","maxLength":50},"maxItems":20},"featured_service_ids":{"type":["array","null"],"items":{"type":"integer"},"maxItems":5},"featured_staff_ids":{"type":["array","null"],"items":{"type":"integer"},"maxItems":5},"about":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":50000},"uz":{"type":["string","null"],"maxLength":50000},"ru":{"type":["string","null"],"maxLength":50000}}},"gallery":{"type":["array","null"],"items":{"type":"string","maxLength":500},"maxItems":20},"social_links":{"type":["array","null"],"items":{"type":"string","format":"uri","maxLength":500},"maxItems":10}},"title":"UpdateOrganizationProfileRequest"},"UpdateOrganizationRequest":{"type":"object","properties":{"address":{"type":["string","null"],"maxLength":255},"district":{"type":["string","null"],"maxLength":100},"city":{"type":["string","null"],"maxLength":255},"state":{"type":["string","null"],"maxLength":255},"country":{"type":["string","null"],"maxLength":255},"postal_code":{"type":["string","null"],"maxLength":50},"timezone":{"type":["string","null"],"maxLength":100},"phone":{"type":["string","null"],"maxLength":50},"email":{"type":["string","null"],"format":"email","maxLength":255},"website":{"type":["string","null"],"format":"uri","maxLength":255},"logo":{"type":["string","null"],"maxLength":500},"default_currency":{"type":["string","null"],"minLength":3,"maxLength":3},"allow_join_requests":{"type":"boolean"},"business_name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"specialty":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":1000},"uz":{"type":["string","null"],"maxLength":1000},"ru":{"type":["string","null"],"maxLength":1000}}}},"title":"UpdateOrganizationRequest"},"UpdateOrganizationSettingsRequest":{"type":"object","properties":{"settings":{"type":"object","properties":{"booking_min_lead_hours":{"type":"integer","minimum":0,"maximum":168},"booking_max_lead_days":{"type":"integer","description":"0 to 7 days in hours","minimum":1,"maximum":365},"waitlist_enabled":{"type":"boolean","description":"1 to 365 days"},"waitlist_auto_promote":{"type":"boolean"},"waitlist_promotion_window_hours":{"type":"integer","minimum":1,"maximum":48},"cancellation_min_hours":{"type":"integer","minimum":0,"maximum":720},"reschedule_min_hours":{"type":"integer","minimum":0,"maximum":720}}}},"required":["settings"],"title":"UpdateOrganizationSettingsRequest"},"UpdateProfileRequest":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255},"locale":{"type":"string","description":"Written back when the user switches language in the app, so the\nbot, email and push follow the same choice.","enum":["en","uz","ru"]}},"title":"UpdateProfileRequest"},"UpdateReviewModerationRequest":{"type":"object","properties":{"is_public":{"type":"boolean"}},"required":["is_public"],"title":"UpdateReviewModerationRequest"},"UpdateReviewRequest":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":["string","null"],"maxLength":1000},"is_public":{"type":"boolean"}},"title":"UpdateReviewRequest"},"UpdateScheduleEntryRequest":{"type":"object","properties":{"is_recurring":{"type":"boolean"},"new_is_recurring":{"type":["boolean","null"]},"day_of_week":{"type":["integer","null"],"minimum":0,"maximum":6},"date":{"type":["string","null"],"format":"date"},"start_time":{"type":["string","null"]},"end_time":{"type":["string","null"]},"staff_id":{"type":["integer","null"]},"service_id":{"type":["integer","null"]},"is_available":{"type":"boolean"},"reason":{"type":["string","null"],"maxLength":255}},"required":["is_recurring"],"title":"UpdateScheduleEntryRequest"},"UpdateServiceRequest":{"type":"object","properties":{"duration":{"type":"integer","minimum":5,"maximum":480},"buffer_before":{"type":"integer","minimum":0,"maximum":60},"buffer_after":{"type":"integer","minimum":0,"maximum":60},"price":{"type":"number","minimum":0},"currency":{"type":"string","minLength":3,"maxLength":3},"category_id":{"type":["integer","null"]},"is_active":{"type":"boolean"},"prepay_policy":{"type":["string","null"],"enum":["none","partial","full"]},"prepay_percentage":{"type":["integer","null"],"minimum":1,"maximum":100},"name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":1000},"uz":{"type":["string","null"],"maxLength":1000},"ru":{"type":["string","null"],"maxLength":1000}}},"staff_ids":{"type":"array","items":{"type":"integer"}}},"title":"UpdateServiceRequest"},"UpdateStaffAvailabilityRequest":{"type":"object","properties":{"availabilities":{"type":"array","items":{"type":"object","properties":{"day_of_week":{"type":"integer","minimum":0,"maximum":6},"start_time":{"type":"string"},"end_time":{"type":"string"},"is_available":{"type":"boolean"},"service_id":{"type":"integer"}},"required":["day_of_week","start_time","end_time","is_available","service_id"]}}},"required":["availabilities"],"title":"UpdateStaffAvailabilityRequest"},"UpdateStaffNotificationPreferenceRequest":{"type":"object","properties":{"telegram_muted":{"type":"boolean"},"muted_until":{"type":["string","null"],"format":"date-time"},"daily_digest_enabled":{"type":["boolean","null"],"description":"Null means \"inherit whatever the business set\"."},"daily_digest_time":{"type":["string","null"]},"quiet_hours_enabled":{"type":["boolean","null"]},"quiet_hours_start":{"type":["string","null"]},"quiet_hours_end":{"type":["string","null"]},"event_overrides":{"type":"array","items":{"type":"string","enum":["instant","digest","off"]}}},"title":"UpdateStaffNotificationPreferenceRequest"},"UpdateStaffRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"slug":{"type":["string","null"],"maxLength":255},"avatar":{"type":["string","null"]},"email":{"type":"string","format":"email","maxLength":255},"phone":{"type":["string","null"],"maxLength":20},"branch_id":{"type":["integer","null"]},"is_active":{"type":"boolean"},"is_profile_public":{"type":"boolean"},"display_name":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"position":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"bio":{"type":"object","properties":{"en":{"type":["string","null"]},"uz":{"type":["string","null"]},"ru":{"type":["string","null"]}}},"roles":{"type":"array","items":{"type":"string","enum":["owner","manager","service_provider","receptionist"]}},"meta_title":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":255},"uz":{"type":["string","null"],"maxLength":255},"ru":{"type":["string","null"],"maxLength":255}}},"meta_description":{"type":"object","properties":{"en":{"type":["string","null"],"maxLength":500},"uz":{"type":["string","null"],"maxLength":500},"ru":{"type":["string","null"],"maxLength":500}}},"service_ids":{"type":"array","items":{"type":"integer"}}},"title":"UpdateStaffRequest"},"UpdateStaffServicesRequest":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"price_override":{"type":["number","null"],"minimum":0},"duration_override":{"type":["integer","null"],"minimum":1}},"required":["id"]}}},"required":["services"],"title":"UpdateStaffServicesRequest"},"UploadMediaRequest":{"type":"object","properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","maxLength":10240},"folder":{"type":["string","null"],"maxLength":50}},"required":["file"],"title":"UploadMediaRequest"},"UpsertPaymentSettingRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["click","payme","stripe","uzum"]},"is_enabled":{"type":"boolean"},"prepay_policy":{"type":"string","description":"Prepay configuration","enum":["none","partial","full"]},"prepay_percentage":{"type":["integer","null"],"minimum":1,"maximum":100},"refund_on_cancellation":{"type":"boolean","description":"Refund policy"},"refund_deadline_hours":{"type":["integer","null"],"minimum":0,"maximum":720},"auto_remind_unpaid":{"type":"boolean","description":"max 30 days\nReminders"},"remind_after_minutes":{"type":["integer","null"],"minimum":5,"maximum":1440},"success_url":{"type":["string","null"],"format":"uri","description":"max 24 hours\nURL overrides","maxLength":500},"cancel_url":{"type":["string","null"],"format":"uri","maxLength":500},"credentials":{"type":["array","null"],"description":"Provider-specific credentials (stored encrypted)","items":{"type":["string","null"],"maxLength":1000}}},"required":["provider","is_enabled","prepay_policy","refund_on_cancellation","auto_remind_unpaid"],"title":"UpsertPaymentSettingRequest"},"UserResource":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"telegram_id":{"type":["string","null"]}},"required":["id","name","email","phone","telegram_id"],"title":"UserResource"},"ValidatePartnerCodeRequest":{"type":"object","properties":{"code":{"type":"string","maxLength":20}},"required":["code"],"title":"ValidatePartnerCodeRequest"},"VerifyEmailChangeRequest":{"type":"object","properties":{"code":{"type":"string","minLength":6,"maxLength":6}},"required":["code"],"title":"VerifyEmailChangeRequest"},"VerifyEmailRequest":{"type":"object","properties":{"email":{"type":"string","format":"email"},"code":{"type":"string"}},"required":["email","code"],"title":"VerifyEmailRequest"},"VerifyPhoneChangeRequest":{"type":"object","properties":{"code":{"type":"string","minLength":6,"maxLength":6}},"required":["code"],"title":"VerifyPhoneChangeRequest"},"VerifyPhoneRequest":{"type":"object","properties":{"phone":{"type":"string"},"code":{"type":"string"}},"required":["phone","code"],"title":"VerifyPhoneRequest"},"WaitlistEntryResource":{"type":"object","properties":{"id":{"type":"integer"},"status":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WaitlistStatus"}]},"preferred_date":{"type":"string"},"preferred_time_slot":{"type":["string","null"]},"position":{"type":"integer"},"notes":{"type":["string","null"]},"added_by":{"type":"string"},"offered_at":{"type":"string"},"offer_expires_at":{"type":"string"},"client":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}},"required":["id","name","email","phone"]},"service":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"duration":{"type":"integer"},"price":{"type":"string"},"currency":{"type":"string"}},"required":["id","name","duration","price","currency"]},"staff":{"type":["object","null"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"required":["id","name"]},"offered_appointment":{"anyOf":[{"$ref":"#/components/schemas/AppointmentResource"},{"type":"null"}]},"can_cancel":{"type":"string"},"can_accept":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","status","preferred_date","preferred_time_slot","position","notes","added_by","offered_at","offer_expires_at","can_cancel","can_accept","created_at","updated_at"],"title":"WaitlistEntryResource"},"WaitlistStatus":{"type":"string","enum":["waiting","offered","booked","expired","cancelled"],"title":"WaitlistStatus"}},"responses":{"ValidationException":{"description":"Validation error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Errors overview."},"errors":{"type":"object","description":"A detailed description of each field that failed validation.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["message","errors"]}}}},"ModelNotFoundException":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview."}},"required":["message"]}}}},"AuthenticationException":{"description":"Unauthenticated","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview."}},"required":["message"]}}}},"AuthorizationException":{"description":"Authorization error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error overview."}},"required":["message"]}}}}}}}