AI Monorepo API
tRPC API Documentation
Analytics
Distinct talent, locations, and entry count for today's schedule.
{
today: any
}
{
talentCount: number
locationCount: number
scheduleCount: number
}
Roster size split into on-site (active) vs off-roster (hidden) talent.
{
total: number
active: number
hidden: number
}
Schedule count per day for the current week (MonβSun).
{
today: any
}
Array<{
date: string
value: number
}>
Distinct talent scheduled at least one day this week (MonβSun).
{
today: any
}
number
Unique talent count per location for the current week.
{
today: any
}
Array<{
name: string
value: number
}>
Count of roster talent missing each profile field.
Array<{
name: "Photos" | "Bio" | "Tagline" | "Age" | "Height" | "Weight" | "Measurements" | "Fees" | "Menus" | "Services" | "Notes"
talents: string[]
}>
Each talent's all-time booking rhythm: calls per day worked, the same split by weekday, and the hours her calls start.
Array<{
talentId: string
nickname: string
totalCalls: number
daysWorked: number
avgPerDay: number
busiestWeekday: number | null
busiestHour: number | null
byWeekday: Array<{
weekday: number
calls: number
daysWorked: number
avgPerDay: number
}>
byHour: Array<{
hour: number
calls: number
}>
}>
Appointment
A schedule with its appointments and the derived day totals β the daily tracker detail summary (Due / Paid / Balance + the Credit/Paid/Miss state)
{
scheduleId: string
}
{
schedule: {
id: string
talentId: string
talentName: string
locationId: string
locationName: string
locationDeleted: boolean
city: string
date: string | any
category: "Hotel" | "Airbnb" | "Condo"
talentBookOnFee: number | null
flatFee: number | null
bookOn: number | null
notes?: string | null
envelopeDroppedAt: string | any | null
}
appointments: Array<{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
paid: number
}>
due: number
paid: number
balance: number
status: "credit" | "paid" | "miss"
cancellationIncome: number
}
A day's live appointments across every schedule β the booking grid's one read (LUX-246); cancelled and carrier rows never appear
{
date: any
}
Array<{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
paid: number
durationMinutes: number | null
menuType: string | null
menuPrice: number | null
price: number
}>
One appointment for the edit form
{
id: string
}
{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
}
A client's appointments in this brand (newest first) β the picker for applying a credit to a booking (LUX-113)
{
clientId: string
}
Array<{
id: string
date: string | any
startTime: string | null
talentName: string
locationName: string
}>
Books an appointment; fee and per-line service fees are captured from the menu catalog, never from the client
{
scheduleId: string
clientId: string
menuId: string
bookedByUserId: string
phoneNumberId?: string | null
paidToUserId?: string | null
startTime?: string | null
discount: number
confirmed: boolean
isIndy: boolean
notes?: string | null
services: Array<{
menuServiceId: string
}>
}
{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
}
Historical import only (LUX-120): replaces a schedule-day's synthesized appointments + their payments, and upserts the day's book-on onto its daily report β one transaction, so the day lands whole or not at all (D92). The DOCUMENTED D67 EXCEPTION β the only write that accepts an explicit fee, because the sheet's total is history and re-capturing it from the talent's current Menu.fee would import today's price. Idempotent: only rows marked imported are replaced, never an operator's real booking. 404 unless the schedule belongs to the requesting company
{
scheduleId: string
clientId: string
bookedByUserId?: string | null
callCount: number
serviceTotal: number
payments: Array<{
method: "EMT" | "AmazonGiftCard" | "Cash" | "TalentCredit"
amount: number
}>
bookOn: number
bookerSplit: Array<{
bookedByUserId: string
calls: number
}>
calls?: Array<{
fee: number
startTime?: string | null
notes?: string | null
isIndy: boolean
menuId?: string | null
}>
cancellations: Array<{
fee: number
deposit: number
startTime?: string | null
notes?: string | null
method?: "EMT" | "AmazonGiftCard" | "Cash" | "TalentCredit" | null
}>
}
{
replaced: number
dayExisted: boolean
appointments: Array<{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
}>
}
Edits an appointment; re-captures the fee and replaces the service lines
{
scheduleId: string
clientId: string
menuId: string
bookedByUserId: string
phoneNumberId?: string | null
paidToUserId?: string | null
startTime?: string | null
discount?: number
confirmed?: boolean
isIndy?: boolean
notes?: string | null
services?: Array<{
menuServiceId: string
}>
id: string
}
{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
}
Removes an appointment
{
id: string
}
Schedules in a date range with the derived Due, Paid, Balance and the Credit/Paid/Miss state, computed server-side. An admin reads the whole range; a booker reads only the days she covered a line, Β±1 week of today (LUX-235)
{
startDate: any
endDate: any
}
Array<{
scheduleId: string
date: string | any
talentName: string
locationName: string
city: string
calls: number
due: number
paid: number
balance: number
status: "credit" | "paid" | "miss"
bookOn: number | null
cancellationIncome: number
}>
One page of appointments across the company's talents, joined to its schedule for display β the browse-by-date list. Every filter (date range, talent, search) is applied server-side; omitting both date bounds is 'All dates'
{
page: number
pageSize: number
startDate?: any
endDate?: any
talentId?: string
search?: string
}
{
items: Array<{
id: string
scheduleId: string
startTime: string | null
clientId: string
clientName: string
menuId: string | null
menuLabel: string | null
fee: number
discount: number
bookedByUserId: string | null
bookerName: string | null
bookerPay: number
paidToUserId: string | null
payeeName: string | null
confirmed: boolean
services: Array<{
id: string
appointmentId: string
menuServiceId: string
serviceName: string
fee: number
}>
notes?: string | null
cancelledAt: string | any | null
isCarrier: boolean
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
date: string | any
talentId: string
talentName: string
locationName: string
city: string
}>
total: number
}
Auth
Authenticate with email and password
{
email: string
password: string
}
{
token: string | null
user: {
id: string
email: string
name: string | null
image: string | null
emailVerified: boolean
}
}
Booker
Returns all bookers (Users with role 'booker'), name ascending, each with its pay rate (null until set)
Array<{
id: string
name: string
payRate: number | null
active: boolean
}>
Deactivates a booker or brings her back (LUX-250). Deactivating ends her login and clears her phone coverage from `today` on; her bookings, pay rate and payroll history are untouched, and the days she already worked stay on the grid. Bookers only β any other role is NOT_FOUND. Deactivating your own account is FORBIDDEN
{
userId: string
active: boolean
today: any
}
any
Sets a booker's pay rate β whole dollars per booked appointment (D76); upserts by user. New appointments stamp this rate; past ones are unchanged
{
userId: string
amount: number
}
Per-booker MonβSun weeks: calls booked, pay owed (Ξ£ stamped bookerPay), and whether the week has been paid β most recent first (D76/D77)
Array<{
userId: string
bookerName: string
weekStart: string | any
weekEnd: string | any
calls: number
amount: number
cancellationPay: number
paidOn: string | any | null
paidAmount: number | null
}>
Marks one booker's MonβSun week as paid, snapshotting the amount the server computes for that week; confirming the same week again overwrites rather than double-paying
{
userId: string
weekStart: string | any
paidOn: string | any
}
BookerSchedule
Returns booker coverage entries for an inclusive date range, date then startsAt ascending
{
from: any
to: any
}
Array<{
id: string
userId: string
phoneNumberId: string
date: string | any
startsAt: string
}>
Replaces one number+date's coverage wholesale β the final list of takeovers for that day; empty clears it. A booker already covering another number that day is a CONFLICT (one shift per day)
{
phoneNumberId: string
date: any
shifts: Array<{
userId: string
startsAt: string
}>
}
any
City
Returns the requesting company's cities in display order
Array<{
id: string
createdAt: string | any
updatedAt: string | any
name: string
sortOrder: number
}>
Batch-update the display order of city sections for the requesting company
{
orderedIds: string[]
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
name: string
sortOrder: number
}>
Onboards a city by name for the requesting company; returns the existing city if the name is already used
{
name: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
sortOrder: number
}
Renames a city owned by the requesting company; 404 unless it belongs to the company, 409 if the name is already used
{
id: string
name: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
sortOrder: number
}
Deletes a city owned by the requesting company; 404 unless it belongs to the company, 400 while it still has locations
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
sortOrder: number
}
Client
One page of clients (global across brands), identity fields only, with the total matching the search
{
page: number
pageSize: number
search?: string
}
{
items: Array<{
id: string
code: string
name: string | null
phone: string
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
isConfirmed: boolean
}>
total: number
}
Returns every client unpaginated, identity fields only β for the importerβs phone dedup index; the admin list uses `client.list`
Array<{
id: string
code: string
name: string | null
phone: string
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
isConfirmed: boolean
}>
Returns the named clients in the list projection. Ids are deduped and unknown ids are OMITTED, so the result may be shorter than the input β it is never an error
{
ids: string[]
}
Array<{
id: string
code: string
name: string | null
phone: string
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
isConfirmed: boolean
}>
Returns a client by ID, with the brands they booked through
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
code: string
name: string | null
phone: string
email: string | null
city: string | null
ageRange: string | null
ethnicity: string | null
notes: string | null
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
blacklistReason: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues" | null
isConfirmed: boolean
brands: string[]
otherPhones: string[]
}
How many times a client has booked and the few bookings that matter while answering them β upcoming soonest-first, then recent past. Across every brand, cancellations excluded. `today` is the caller's local date.
{
clientId: string
today: any
}
{
total: number
visits: Array<{
id: string
date: string | any
startTime: string | null
talentName: string
locationName: string | null
city: string | null
upcoming: boolean
locationId: string | null
}>
}
What a client usually books, ranked most-requested first: package, extras, and the talent they book. Counts exactly what `client.visits` counts β every non-cancelled booking across every brand, upcoming included β so the two never disagree.
{
clientId: string
}
{
total: number
firstBookedAt: string | any | null
packages: Array<{
label: string
count: number
}>
extras: Array<{
label: string
count: number
}>
talent: Array<{
label: string
count: number
lastBooked: string | any
}>
visits: Array<{
id: string
date: string | any
startTime: string | null
talentName: string
locationName: string | null
city: string | null
menuLabel: string | null
extras: string[]
}>
}
Creates a client β phone is the global dedup key
{
name?: any | null
phone: string
email?: string | null
city?: string | null
ageRange?: "20-30" | "30-40" | "40-50" | "50+" | null
ethnicity?: string | null
notes?: string | null
cafHandle?: string | null
perbHandle?: string | null
isBlacklisted?: boolean
blacklistReason?: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues" | null
isConfirmed?: boolean
}
{
id: string
createdAt: string | any
updatedAt: string | any
code: string
name: string | null
phone: string
email: string | null
city: string | null
ageRange: string | null
ethnicity: string | null
notes: string | null
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
blacklistReason: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues" | null
isConfirmed: boolean
}
Updates a client
{
name?: any | null
phone?: string
email?: string | null
city?: string | null
ageRange?: "20-30" | "30-40" | "40-50" | "50+" | null
ethnicity?: string | null
notes?: string | null
cafHandle?: string | null
perbHandle?: string | null
isBlacklisted?: boolean
blacklistReason?: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues" | null
isConfirmed?: boolean
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
code: string
name: string | null
phone: string
email: string | null
city: string | null
ageRange: string | null
ethnicity: string | null
notes: string | null
cafHandle: string | null
perbHandle: string | null
isBlacklisted: boolean
blacklistReason: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues" | null
isConfirmed: boolean
}
Folds one client profile into another and retires it: bookings, credits, conversations and the Don't-See list move to the surviving client, whose code and phone are kept, and the retired profile's number stays linked so texts from it resolve to the survivor. Irreversible.
{
keepClientId: string
mergeClientId: string
}
{
keptCode: string
retiredCode: string
linkedPhone: string
}
Returns the ids of talents on a client's Don't-See list
{
clientId: string
}
string[]
Adds talents to a client's Don't-See list, removing none β returns how many were new
{
clientId: string
talentIds: string[]
}
{
added: number
talentIds: string[]
}
Marks a client as confirmed, never the reverse β returns whether this call changed it
{
clientId: string
}
{
promoted: boolean
}
Blocks a client who carries no reason, never re-categorizing one who does β returns whether this call changed it
{
clientId: string
blacklistReason: "NoShow" | "TimeWaster" | "Aggressive" | "NoDeposit" | "NonCooperative" | "HygieneIssues"
}
{
blocked: boolean
}
Places a client who has no city, never moving one who does β returns whether this call changed it
{
clientId: string
city: string
}
{
filled: boolean
}
Replaces a client's Don't-See list β the talents who won't see this client
{
clientId: string
talentIds: string[]
}
string[]
ClientCredit
A client's prepaid / cancellation credits in this brand, newest first
{
clientId: string
}
Array<{
id: string
clientId: string
amount: number
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit" | null
status: "held" | "applied" | "cancellationFee"
talentAmount: number | null
bookerFee: number | null
agencyAmount: number | null
note: string | null
createdAt: string | any
appliedBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
cancelledBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
}>
Records a client prepayment as a held credit (>= $50 minimum, D87) β never a Payment
{
clientId: string
amount: number
method: "EMT" | "AmazonGiftCard" | "Cash"
note?: string
}
{
id: string
clientId: string
amount: number
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit" | null
status: "held" | "applied" | "cancellationFee"
talentAmount: number | null
bookerFee: number | null
agencyAmount: number | null
note: string | null
createdAt: string | any
appliedBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
cancelledBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
}
Applies a held credit to a booking β creates a Payment(method:Credit) for the full amount so the tracker Paid rolls up (D87)
{
id: string
appointmentId: string
}
{
id: string
clientId: string
amount: number
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit" | null
status: "held" | "applied" | "cancellationFee"
talentAmount: number | null
bookerFee: number | null
agencyAmount: number | null
note: string | null
createdAt: string | any
appliedBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
cancelledBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
}
Uses a held credit as a cancellation fee behind a specific cancelled booking β stamps the talent Β½ / booker $25 / agency surplus split and links the booking so the talent-day income + booker-week $25 report; no Payment (D87/D95)
{
id: string
cancelledAppointmentId: string
}
{
id: string
clientId: string
amount: number
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit" | null
status: "held" | "applied" | "cancellationFee"
talentAmount: number | null
bookerFee: number | null
agencyAmount: number | null
note: string | null
createdAt: string | any
appliedBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
cancelledBooking: {
id: string
date: string | any
talentName: string
locationName: string
} | any | null
}
Removes a mistaken held credit β a consumed (applied / cancellation-fee) credit is immutable
{
id: string
}
Company
Returns all companies
Array<{
id: string
createdAt: string | any
updatedAt: string | any
name: string
slug: string
defaultPhoneNumberId: string | null
imageBrand: "LuxWatermark" | "Clean"
}>
Returns the requesting company's default (house) phone, or null when unset β the public fallback for talent contact numbers
{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
Creates a new company
{
name: string
slug: string
defaultPhoneNumberId?: string | null
imageBrand?: "LuxWatermark" | "Clean"
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
slug: string
defaultPhoneNumberId: string | null
imageBrand: "LuxWatermark" | "Clean"
}
Updates a company
{
name?: string
slug?: string
defaultPhoneNumberId?: string | null
imageBrand?: "LuxWatermark" | "Clean"
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
slug: string
defaultPhoneNumberId: string | null
imageBrand: "LuxWatermark" | "Clean"
}
Blocked β companies cannot be deleted via the API
{
id: string
}
Events
SSE stream that emits whenever something changed that other operators should see β an SMS, a booking, a payment, a roster edit. Carries the topic only; refetch on event.
Expense
Ad-hoc expenses in a date range (by the date incurred), newest first β the list + the weekly report money-out
{
startDate: any
endDate: any
}
Array<{
id: string
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: string | any
note: string | null
payrollUserId: string | null
allocations: Array<{
locationId: string
locationName: string
city: string
amount: number
}>
}>
One expense with its allocations, or null when not this companyβs
{
id: string
}
{
id: string
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: string | any
note: string | null
payrollUserId: string | null
allocations: Array<{
locationId: string
locationName: string
city: string
amount: number
}>
} | null
Records an expense across 0/1/many locations β the server splits the amount evenly (0 locations = a general cost); allocation shares are derived, never client-sent
{
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: any
note?: string
locationIds: string[]
payrollUserId?: string | null
}
{
id: string
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: string | any
note: string | null
payrollUserId: string | null
allocations: Array<{
locationId: string
locationName: string
city: string
amount: number
}>
}
Updates an expense and replaces its allocation; 404 unless it belongs to the requesting company
{
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: any
note?: string
locationIds?: string[]
payrollUserId?: string | null
id: string
}
{
id: string
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: string | any
note: string | null
payrollUserId: string | null
allocations: Array<{
locationId: string
locationName: string
city: string
amount: number
}>
}
Removes an expense and its allocations
{
id: string
}
FinanceDashboard
Owner business-health roll-up over a period (day / week / month / quarter / year): gross (Ξ£ Due), expenses (ad-hoc + prorated fixed costs), net, and collected cash β each with a delta vs the prior period, plus a trend, by-city and by-category breakdown
{
periodKind: "day" | "week" | "month" | "quarter" | "year"
anchorDate: string
}
{
periodKind: "day" | "week" | "month" | "quarter" | "year"
range: {
startDate: string | any
endDate: string | any
}
kpis: {
gross: {
value: number
previous: number
delta: number
}
expenses: {
value: number
previous: number
delta: number
}
net: {
value: number
previous: number
delta: number
}
collectedCash: {
value: number
previous: number
delta: number
}
cashProfit: {
value: number
previous: number
delta: number
}
}
trend: Array<{
date: string | any
gross: number
expenses: number
net: number
collectedCash: number
}>
byCity: Array<{
city: string
gross: number
spend: number
net: number
}>
businessWide: number
byCategory: Array<{
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation" | "Rent" | "Utilities" | "Internet" | "Insurance" | "Misc"
amount: number
}>
bookerPay: number
}
Per-location leaderboard over a period: each non-Hotel locationβs revenue (Ξ£ Due), prorated fixed costs, allocated expenses, profit and booked-day utilization β ranked client-side by profit / margin / profit-per-booked-day
{
periodKind: "day" | "week" | "month" | "quarter" | "year"
anchorDate: string
}
Array<{
locationId: string
locationName: string
city: string
revenue: number
collectedCash: number
fixedCosts: number
allocatedExpenses: number
bookerPay: number
profit: number
cashProfit: number
bookedDays: number
daysInPeriod: number
}>
One locationβs monthly trend (revenue vs expenses), cost composition (fixed lines + assigned expenses), cumulative investment-vs-return (payback), and booked-day utilization over the last 12 months
{
locationId: string
anchorDate: string
}
{
locationId: string
locationName: string
city: string
months: Array<{
period: string
revenue: number
expenses: number
fixedCosts: number
allocatedExpenses: number
bookerPay: number
bookedDays: number
daysInMonth: number
}>
costComposition: {
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
allocatedExpenses: number
bookerPay: number
}
costCompositionByMonth: Array<{
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
allocatedExpenses: number
bookerPay: number
period: string
}>
investmentReturn: Array<{
period: string
cumulativeInvested: number
cumulativeRevenue: number
}>
}
DailyReport
Upserts a schedule-day's book-on (+ the airbnb/hotel per-date flat fee). The book-on is stored as sent β an editable per-day override (D64). 404 unless the schedule belongs to the requesting company
{
scheduleId: string
flatFee?: number | null
bookOn: number
}
{
id: string
scheduleId: string
flatFee: number | null
bookOn: number
}
File
Returns root images with failed processing status
any[]
Retries processing for a failed image by re-generating missing variants
{
imageId: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
fileId: string
talentId: string
variant: "Original" | "Thumbnail" | "Large"
imageBrand: "LuxWatermark" | "Clean" | null
status: "Processing" | "Completed" | "Failed"
errorMessage: string | null
width: number | null
height: number | null
sortOrder: number
sourceImageId: string | null
file: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
mimeType: string
size: number
blobKey: string
container: string
url: string | null
uploadedById: string | null
} | null
variants: any[]
}
Debug
Throws a test error for Sentry
Image
Returns all images for a talent belonging to the requesting company
{
talentId: string
}
any[]
Returns talentId β thumbnail URL for the requesting company's talents, in the company's image brand
Record<string, string | null>
Returns talentId β thumbnail URL across all companies' talents, in the requesting company's image brand β the admin lists show non-members too
Record<string, string | null>
Creates a new image
{
fileId: string
variant?: "Original" | "Thumbnail" | "Large"
imageBrand?: "LuxWatermark" | "Clean" | null
width?: number | null
height?: number | null
sortOrder?: number
talentId: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
fileId: string
talentId: string
variant: "Original" | "Thumbnail" | "Large"
imageBrand: "LuxWatermark" | "Clean" | null
status: "Processing" | "Completed" | "Failed"
errorMessage: string | null
width: number | null
height: number | null
sortOrder: number
sourceImageId: string | null
file: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
mimeType: string
size: number
blobKey: string
container: string
url: string | null
uploadedById: string | null
} | null
variants: any[]
}
Updates an existing image
{
width?: number | null
height?: number | null
sortOrder?: number
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
fileId: string
talentId: string
variant: "Original" | "Thumbnail" | "Large"
imageBrand: "LuxWatermark" | "Clean" | null
status: "Processing" | "Completed" | "Failed"
errorMessage: string | null
width: number | null
height: number | null
sortOrder: number
sourceImageId: string | null
file: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
mimeType: string
size: number
blobKey: string
container: string
url: string | null
uploadedById: string | null
} | null
variants: any[]
}
Batch-update sort order for a set of images
{
orderedIds: string[]
}
any[]
Returns a short-lived SAS URL for downloading the original blob
{
id: string
}
{
url: string
}
Re-derives a talent's photos for every brand their companies display (e.g. the clean set after adding a LUX model to VIP Kitty). Idempotent β only missing brand variants are rendered.
{
talentId: string
}
{
rendered: number
skipped: number
failed: number
}
Deletes an image and its variants from DB and blob storage
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
fileId: string
talentId: string
variant: "Original" | "Thumbnail" | "Large"
imageBrand: "LuxWatermark" | "Clean" | null
status: "Processing" | "Completed" | "Failed"
errorMessage: string | null
width: number | null
height: number | null
sortOrder: number
sourceImageId: string | null
file: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
mimeType: string
size: number
blobKey: string
container: string
url: string | null
uploadedById: string | null
} | null
variants: any[]
}
Location
Returns the requesting company's locations
Array<{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}>
Returns every live location as a schedule-grid bucket (id, display name, city), ordered city-then-location, with no schedule entries. Condos past their move-out date are excluded (LUX-240) β an ended tenancy takes no new bookings; weeks where it has rows still show it via schedule.weekEntriesAdmin. Takes no date range: it is the same for every week, so the schedule page paints its location list before any week loads and keeps it across week switches. Pair with schedule.weekEntriesAdmin, which supplies that week's days.
Array<{
locationId: string
locationName: string
city: string
cityId: string
}>
Returns a location by ID; 404 unless it belongs to the requesting company
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
Creates a location owned by the requesting company
{
city: string
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName?: string | null
unitNumber?: string | null
street?: string | null
province?: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode?: string | "" | null
arrivalInstructions1?: string | null
arrivalInstructions2?: string | null
emergencyPlan?: string | null
garbageLocation?: string | null
checkInInstructions?: string | null
safeLocation?: string | null
parkingInstructions?: string | null
wifi?: string | null
additionalInfo?: string | null
houseGuidelines?: string[]
faq?: Array<{
question: string
answer: string
}>
capacity?: number | null
phoneNumberId?: string | null
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
Batch-update the display order of locations within a city for the requesting company
{
orderedIds: string[]
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}>
Updates a location owned by the requesting company
{
city?: string
name?: string
category?: "Hotel" | "Airbnb" | "Condo"
hotelName?: string | null
unitNumber?: string | null
street?: string | null
province?: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode?: string | "" | null
arrivalInstructions1?: string | null
arrivalInstructions2?: string | null
emergencyPlan?: string | null
garbageLocation?: string | null
checkInInstructions?: string | null
safeLocation?: string | null
parkingInstructions?: string | null
wifi?: string | null
additionalInfo?: string | null
houseGuidelines?: string[]
faq?: Array<{
question: string
answer: string
}>
capacity?: number | null
phoneNumberId?: string | null
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
Ends a condo's tenancy at a move-out date, or resumes it with null β a dated deactivation, never a delete (D104). Condo only: Airbnb/Hotel are always active
{
id: string
tenancyEndedAt: any | null
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
Returns a location's emergency-plan pictures/videos (LUX-212); scoped to the requesting company
{
locationId: string
}
Array<{
id: string
locationId: string
file: {
name: string
mimeType: string
url: string | null
}
}>
Deletes one emergency-plan picture/video, including its blob; 404 unless its location belongs to the requesting company
{
id: string
}
{
id: string
locationId: string
file: {
name: string
mimeType: string
url: string | null
}
}
Deletes a location owned by the requesting company
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
The requesting company's soft-deleted locations, recoverable via location.restore (LUX-203)
Array<{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
deletedAt: string | any
}>
Restores a soft-deleted location owned by the requesting company (LUX-203); NOT_FOUND when the id is not deleted or not owned
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
city: string | any
name: string
category: "Hotel" | "Airbnb" | "Condo"
hotelName: string | null
unitNumber: string | null
street: string | null
province: "AB" | "BC" | "MB" | "NB" | "NL" | "NS" | "NT" | "NU" | "ON" | "PE" | "QC" | "SK" | "YT" | null
postalCode: string | null
phoneNumberId: string | null
phoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
capacity: number | null
arrivalInstructions1: string | null
arrivalInstructions2: string | null
emergencyPlan: string | null
garbageLocation: string | null
checkInInstructions: string | null
safeLocation: string | null
parkingInstructions: string | null
wifi: string | null
additionalInfo: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
tenancyEndedAt: string | any | null
}
LocationFixedCost
A location's operating costs for a month (YYYY-MM), or null when none are set
{
locationId: string
period: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
locationId: string
period: string
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
} | null
The nearest month with costs β the most recent one before the given month, or failing that the nearest later one (backfill) β the source for "copy latest month"; null when no other month has costs
{
locationId: string
period: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
locationId: string
period: string
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
} | null
Upserts a month's operating costs; 404 unless the location belongs to the requesting company
{
locationId: string
period: string
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
}
{
id: string
createdAt: string | any
updatedAt: string | any
locationId: string
period: string
rent: number
utilities: number
internet: number
insurance: number
cleaning: number
supplies: number
misc: number
}
LocationNote
Returns the requesting company's location notes whose date falls in the window, scoped via location ownership.
{
startDate: any
endDate: any
}
Array<{
id: string
createdAt: string | any
locationId: string
date: string | any
text: string
createdByName: string | null
}>
Every add, edit and delete a location's day has seen β including notes that were deleted. Newest first, scoped via location ownership.
{
locationId: string
date: any
}
Array<{
id: string
noteId: string
action: "Created" | "Updated" | "Deleted"
text: string
createdByName: string | null
createdAt: string | any
}>
Creates a note pinned to one of the requesting company's locations on a specific day.
{
locationId: string
date: any
text: string
}
{
id: string
createdAt: string | any
locationId: string
date: string | any
text: string
createdByName: string | null
}
Updates a note on one of the requesting company's locations.
{
text?: string
id: string
}
{
id: string
createdAt: string | any
locationId: string
date: string | any
text: string
createdByName: string | null
}
Deletes a note on one of the requesting company's locations.
{
id: string
}
{
id: string
createdAt: string | any
locationId: string
date: string | any
text: string
createdByName: string | null
}
LocationPnl
Per-location profit for a month on both bases β earned (Ξ£ Due, incl. book-on) and cash (Ξ£ Paid) β each less fixed costs, allocated expenses and booker pay, plus the off-roster reconciling line
{
period: string
}
{
rows: Array<{
locationId: string
locationName: string
city: string
revenue: number
collectedCash: number
fixedCosts: number
allocatedExpenses: number
bookerPay: number
profit: number
cashProfit: number
}>
offRoster: {
revenue: number
collectedCash: number
fixedCosts: number
allocatedExpenses: number
bookerPay: number
profit: number
cashProfit: number
}
}
Notification
One page of the signed-in userβs notifications, newest first.
{
page: number
pageSize: number
}
{
items: Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "SmsReceived" | "TalentChangeRequested" | "BookingCreated"
entityId: string
title: string
body: string | null
readAt: string | any | null
}>
total: number
}
One of the signed-in user's notifications by id β null for anyone else's.
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
type: "SmsReceived" | "TalentChangeRequested" | "BookingCreated"
entityId: string
title: string
body: string | null
readAt: string | any | null
} | null
How many notifications the signed-in user has not read.
{
count: number
}
Marks one of the signed-in userβs notifications read. Idempotent.
{
id: string
}
any
Marks every unread notification of the signed-in user.
any
VAPID public key the browser subscribes under; null while web push is unconfigured.
{
publicKey: string | null
}
Registers this browserβs push subscription for the signed-in user. Idempotent per endpoint.
{
endpoint: string
keys: {
p256dh: string
auth: string
}
}
any
Removes this browserβs push subscription. Another userβs endpoint is a silent no-op.
{
endpoint: string
}
any
SSE stream that emits whenever the signed-in user gets a notification.
Payment
An appointment's recorded payment lines (the Payments card) β one or many per appointment, e.g. an e-transfer + cash split
{
appointmentId: string
}
Array<{
id: string
appointmentId: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
emtSenderName: string | null
}>
Records a payment line against an appointment. Only the first line may be a deposit; the client comes from the appointment, never sent
{
appointmentId: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "TalentCredit"
amount: number
isDeposit: boolean
emtSenderName?: string
}
{
id: string
appointmentId: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
emtSenderName: string | null
}
Records a payment against a schedule-day with no booking (LUX-206) β e.g. a talent settling a carried balance on a day she took no calls. The day's carrier booking is found-or-created (the import's money-only-day rule) and the line lands on it; carriers are skipped by every call count
{
scheduleId: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "TalentCredit"
amount: number
emtSenderName?: string
}
{
id: string
appointmentId: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
emtSenderName: string | null
}
Removes a payment line
{
id: string
}
Payroll
The requesting user's own payroll: their booker MonβSun weeks (same aggregation as the admin Booker Payroll screen, filtered to them) and the expenses tagged to their payroll β never anyone else's
{
weeks: Array<{
userId: string
bookerName: string
weekStart: string | any
weekEnd: string | any
calls: number
amount: number
cancellationPay: number
paidOn: string | any | null
paidAmount: number | null
}>
expenses: Array<{
id: string
amount: number
category: "Admin" | "Cleaning" | "Photoshoot" | "Marketing" | "Owner" | "Supplies" | "InitialSetup" | "Accommodation"
incurredOn: string | any
note: string | null
payrollUserId: string | null
allocations: Array<{
locationId: string
locationName: string
city: string
amount: number
}>
}>
}
PhoneNumber
Returns all phone numbers
Array<{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
}>
Returns a phone number by ID
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
}
Creates a new phone number
{
name?: string | null
number: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
}
Updates an existing phone number
{
name?: string | null
number?: string
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
}
Deletes a phone number
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
}
Review
Returns all reviews for a talent, newest first
{
talentId: string
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
talentId: string
content: string
createdByName: string | null
}>
Creates a new talent review
{
talentId: string
content: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
talentId: string
content: string
createdByName: string | null
}
Updates a review
{
content: string
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
talentId: string
content: string
createdByName: string | null
}
Deletes a review
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
talentId: string
content: string
createdByName: string | null
}
Schedule
Returns the requesting company's schedules for today with talent data
{
today: any
}
Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
talentId: string
talent: {
id: string
nickname: string
}
}>
Returns pre-grouped visiting-soon entries (next 60 days)
{
today: any
}
Array<{
talentId: string
nickname: string
city: string
dateLabel: string
}>
Returns the requesting company's schedules in a date range with talent and location data
{
startDate: any
endDate: any
}
Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
talentId: string
talent: {
id: string
nickname: string
}
}>
Returns a week of the requesting company's schedules pre-grouped by city β location β date. Drops soft-deleted-location rows.
{
startDate: any
endDate: any
}
Array<{
city: string
locations: Array<{
locationId: string
locationName: string
deleted: boolean
days: Array<{
date: string | any
entries: Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
talentId: string
talent: {
id: string
nickname: string
}
}>
}>
}>
}>
Returns all schedules for a talent
{
talentId: string
}
Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}>
Returns all schedules for a location
{
locationId: string
}
Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}>
Returns a week's schedule entries bucketed by date, one bucket per POPULATED location β the locations without rows come from location.listForScheduleGrid. Soft-deleted locations appear only when they have rows in the window (flagged deleted), carrying their city so the client can place them.
{
startDate: any
endDate: any
}
Array<{
locationId: string
locationName: string
city: string
cityId: string
deleted: boolean
days: Array<{
date: string | any
entries: Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
talentId: string
talent: {
id: string
nickname: string
}
}>
}>
}>
How booked each scheduled day in the window is: the live calls actually taken on it, and what the talent's history says to expect there. One row per schedule, keyed by `scheduleId` so it joins onto schedule.weekEntriesAdmin. `expected` is null for a talent who has never worked β an absence, not a forecast of none.
{
startDate: any
endDate: any
}
Array<{
scheduleId: string
booked: number
expected: number | null
basis: "weekday" | "overall"
sampleDays: number
}>
A location's all-time booking history: every talent who has worked it with her calls-per-day there, best first, and each weekday's norm (null under three samples β an absence, not a norm of zero). Feeds the schedule grid's day hover card.
{
locationId: string
}
{
talent: Array<{
talentId: string
nickname: string
avgHere: number
daysHere: number
}>
weekdays: Array<{
weekday: number
avg: number | null
sampleDays: number
}>
}
Every location that has ever been staffed, ranked by all-time calls per staffed calendar date, best first. Feeds the Talent dashboard location list; pair with schedule.locationHistoryAdmin for one locationβs detail.
Array<{
locationId: string
name: string
avgPerDay: number
daysWorked: number
}>
Returns the selected company's schedules in a date range (admin; location-ownership, no roster gate)
{
startDate: any
endDate: any
}
Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
talentId: string
talent: {
id: string
nickname: string
}
}>
Creates a new schedule
{
locationId: string
date: any
startTime?: string | null
endTime?: string | null
notes?: string | null
talentId: string
}
{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}
Get-or-create a schedule by its natural key (talent + location + date). Idempotent β returns the row and whether it was newly created. The historical import (LUX-120) uses this as its per-day anchor.
{
locationId: string
date: any
startTime?: string | null
endTime?: string | null
notes?: string | null
talentId: string
}
{
created: boolean
schedule: {
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}
}
Updates an existing schedule. Passing `talentId` re-points the day to another talent (LUX-188) β its appointments and money hang off the schedule, so they follow. Rejects a re-point onto an occupied (talent, location, date) with CONFLICT rather than merging two days.
{
talentId?: string
locationId?: string
date?: any
startTime?: string | null
endTime?: string | null
notes?: string | null
id: string
}
{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}
Deletes a schedule
{
id: string
}
{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}
Service
Returns all services with talent counts
Array<{
id: string
name: string
createdAt: string | any
talentCount: number
}>
Returns a service by ID
{
id: string
}
{
id: string
name: string
createdAt: string | any
}
Creates a new service
{
name: string
}
{
id: string
name: string
createdAt: string | any
}
Updates a service
{
name?: string
id: string
}
{
id: string
name: string
createdAt: string | any
}
Deletes a service
{
id: string
}
{
id: string
name: string
createdAt: string | any
}
MessageRewrite
Returns all message rewrite rules
Array<{
id: string
word: string | null
replacement: string
serviceId: string | null
createdAt: string | any
service: {
id: string
name: string
} | null
}>
Returns a message rewrite rule by ID
{
id: string
}
{
id: string
word: string | null
replacement: string
serviceId: string | null
createdAt: string | any
service: {
id: string
name: string
} | null
}
Creates a new message rewrite rule
{
word?: string | null
replacement: string
serviceId?: string | null
}
{
id: string
word: string | null
replacement: string
serviceId: string | null
createdAt: string | any
service: {
id: string
name: string
} | null
}
Updates a message rewrite rule
{
word?: string | null
replacement: string
serviceId?: string | null
id: string
}
{
id: string
word: string | null
replacement: string
serviceId: string | null
createdAt: string | any
service: {
id: string
name: string
} | null
}
Deletes a message rewrite rule
{
id: string
}
{
id: string
word: string | null
replacement: string
serviceId: string | null
createdAt: string | any
service: {
id: string
name: string
} | null
}
Sms
One page of SMS messages, newest first, optionally filtered to one of our lines or one client. Renders both the inbox and a single thread.
{
page: number
pageSize: number
phoneNumberId?: string
clientId?: string
}
{
items: Array<{
id: string
threadId: string
direction: "Inbound" | "Outbound"
status: "Received" | "Queued" | "Sent" | "Delivered" | "Undelivered" | "Failed"
errorCode: number | null
fromNumber: string
toNumber: string
body: string
readAt: string | any | null
createdAt: string | any
client: {
id: string
code: string
name: string | null
phone: string
isConfirmed: boolean
isBlacklisted: boolean
hasLinkedNumbers: boolean
} | null
phoneNumber: {
id: string
name: string | null
number: string
} | null
sentBy: {
id: string
name: string
} | null
}>
total: number
}
One page of conversations β a client and one of our lines β most recently active first, each with its newest message and unread count.
{
page: number
pageSize: number
phoneNumberId?: string
search?: string
}
{
items: Array<{
id: string
clientId: string | null
phoneNumberId: string | null
unreadCount: number
lastMessage: {
id: string
threadId: string
direction: "Inbound" | "Outbound"
status: "Received" | "Queued" | "Sent" | "Delivered" | "Undelivered" | "Failed"
errorCode: number | null
fromNumber: string
toNumber: string
body: string
readAt: string | any | null
createdAt: string | any
client: {
id: string
code: string
name: string | null
phone: string
isConfirmed: boolean
isBlacklisted: boolean
hasLinkedNumbers: boolean
} | null
phoneNumber: {
id: string
name: string | null
number: string
} | null
sentBy: {
id: string
name: string
} | null
}
}>
total: number
}
Inbound messages nobody has read yet, across the whole inbox β the sidebar badge. Read state is global.
{
count: number
}
One conversation, oldest-first within the page. Page 1 is the most recent messages.
{
page: number
pageSize: number
threadId: string
}
{
items: Array<{
id: string
threadId: string
direction: "Inbound" | "Outbound"
status: "Received" | "Queued" | "Sent" | "Delivered" | "Undelivered" | "Failed"
errorCode: number | null
fromNumber: string
toNumber: string
body: string
readAt: string | any | null
createdAt: string | any
client: {
id: string
code: string
name: string | null
phone: string
isConfirmed: boolean
isBlacklisted: boolean
hasLinkedNumbers: boolean
} | null
phoneNumber: {
id: string
name: string | null
number: string
} | null
sentBy: {
id: string
name: string
} | null
}>
total: number
}
The non-message rows of one conversation, oldest first β the client's bookings and payments. Client-scoped, not thread-scoped: nothing records which conversation an event belongs to, so a client who texts two of our lines sees the same event on both. Imported rows are excluded from both, cancelled bookings from the bookings; a payment on a cancelled booking still shows, and system-created credit payments do not.
{
threadId: string
}
{
events: Array<{
type: "booking" | "payment"
id: string
at: string | any
appointmentId: string
talentName: string
date: string | any
startTime?: string | null
amount?: number
isDeposit?: boolean
method?: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
}>
}
Clears the unread flag on every inbound message in one conversation. Read state is global β the inbox is one shared queue.
{
threadId: string
}
{
count: number
}
Sends a text to a client from one of our lines and records it against the sending user.
{
threadId: string
body: string
}
{
id: string
threadId: string
direction: "Inbound" | "Outbound"
status: "Received" | "Queued" | "Sent" | "Delivered" | "Undelivered" | "Failed"
errorCode: number | null
fromNumber: string
toNumber: string
body: string
readAt: string | any | null
createdAt: string | any
client: {
id: string
code: string
name: string | null
phone: string
isConfirmed: boolean
isBlacklisted: boolean
hasLinkedNumbers: boolean
} | null
phoneNumber: {
id: string
name: string | null
number: string
} | null
sentBy: {
id: string
name: string
} | null
}
Tag
Returns all tags
Array<{
id: string
createdAt: string | any
updatedAt: string | any
name: string
}>
Returns a tag by ID
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
Creates a new tag
{
name: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
Updates a tag
{
name?: string
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
Deletes a tag
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
Talent
Returns the requesting companyβs talents for the public roster, including service names for the filter UI
Array<{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
images: any[]
menuServices: Array<{
service: {
name: string
}
}>
}>
Returns the requesting companyβs talents with images, sorted with today's available first
{
today: any
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
images: any[]
}>
Returns the requesting companyβs talents (with images) scheduled for today, including the city they are in today
{
today: any
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
images: any[]
city: string
startTime: string | null
endTime: string | null
}>
Returns a talent by ID with relations; 404 unless the talent belongs to the requesting company
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
defaultPhoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
menus: Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "Regular" | "Vip"
durationMinutes: number
price: number
}>
menuServices: Array<{
id: string
serviceId: string
excludedFromPromo: boolean
includedInVip: boolean
price: number | null
service: {
id: string
name: string
createdAt: string | any
}
}>
schedules: Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}>
images: any[]
}
Returns a talent by nickname with relations; 404 unless the talent belongs to the requesting company
{
nickname: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
defaultPhoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
menus: Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "Regular" | "Vip"
durationMinutes: number
price: number
}>
menuServices: Array<{
id: string
serviceId: string
excludedFromPromo: boolean
includedInVip: boolean
price: number | null
service: {
id: string
name: string
createdAt: string | any
}
}>
schedules: Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}>
images: any[]
}
Returns lightweight talent list (all companies) with a `member` flag for the requesting company
Array<{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
badge: "Visiting" | "Star" | "Vip" | "New" | null
tagline: string | null
member: boolean
companies: string[]
}>
Returns a talent by nickname across all companies, with a `member` flag for the requesting company
{
nickname: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
defaultPhoneNumber?: {
id: string
createdAt: string | any
updatedAt: string | any
name: string | null
number: string
} | null
tags: Array<{
tag: {
id: string
createdAt: string | any
updatedAt: string | any
name: string
}
}>
menus: Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "Regular" | "Vip"
durationMinutes: number
price: number
}>
menuServices: Array<{
id: string
serviceId: string
excludedFromPromo: boolean
includedInVip: boolean
price: number | null
service: {
id: string
name: string
createdAt: string | any
}
}>
schedules: Array<{
id: string
locationId: string
date: string | any
startTime: string | null
endTime: string | null
notes: string | null
location: {
id: string
city: string | any
name: string
phoneNumberId: string | null
phoneNumber?: {
id: string
name: string | null
number: string
} | null
tenancyEndedAt: string | any | null
deletedAt: string | any | null
}
}>
images: any[]
member: boolean
}
Admin-only forum-ad notes for a talent
{
id: string
}
{
notes: string | null
}
Returns the companies a talent belongs to
{
talentId: string
}
Array<{
companyId: string
companySlug: string
companyName: string
}>
Adds a talent to or removes a talent from a company; returns the updated membership list
{
talentId: string
companyId: string
member: boolean
}
Array<{
companyId: string
companySlug: string
companyName: string
}>
Returns the ids of clients on a talent's Don't-See list
{
talentId: string
}
string[]
Replaces a talent's Don't-See list β the clients this talent won't see
{
talentId: string
clientIds: string[]
}
string[]
Returns the linked login's phone number β null means the talent cannot sign in to the staff portal
{
talentId: string
}
{
phoneNumber: string | null
}
Sets or removes the phone number this talent signs in to the staff portal with (LUX-276). Setting a number mints a login if she has none; removing it revokes her sessions
{
talentId: string
phoneNumber: any | null
}
{
phoneNumber: string | null
}
The requesting user's own talent profile β the talent linked to their account, never anyone else's; null for an admin with no talent link
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
} | null
The requesting talent's own MonβSun week: each scheduled day's venue, shift times, live booking count and her own book-on fee
{
weekStart: any
}
{
startDate: string | any
endDate: string | any
days: Array<{
scheduleId: string
date: string | any
locationId: string
locationPhone: string | null
locationName: string
city: string
street: string | null
startTime: string | null
endTime: string | null
bookingCount: number
bookOnFee: number | null
envelopeDroppedAt: string | any | null
}>
}
The requesting talent's own scheduled days over one calendar month β the Tours calendar's schedule side (LUX-268)
{
month: string
}
{
startDate: string | any
endDate: string | any
days: Array<{
scheduleId: string
date: string | any
locationId: string
locationPhone: string | null
locationName: string
city: string
street: string | null
startTime: string | null
endTime: string | null
bookingCount: number
bookOnFee: number | null
envelopeDroppedAt: string | any | null
}>
}
The venues on the requesting talent's own roster, each with its talent-facing content: getting-in text, house guidelines, FAQ and the emergency plan with its pictures
Array<{
id: string
name: string
city: string
street: string | null
unitNumber: string | null
phone: string | null
checkInInstructions: string | null
houseGuidelines: string[]
faq: Array<{
question: string
answer: string
}>
emergencyPlan: string | null
emergencyMedia: Array<{
id: string
url: string
mimeType: string
}>
}>
The requesting talent's own bookings on one day, each with its client display, services, payments and owed/paid balance
{
date: any
}
Array<{
id: string
scheduleId: string
startTime: string | null
clientName: string
menuLabel: string | null
fee: number
discount: number
confirmed: boolean
notes?: string | null
cancelledAt: string | any | null
bookerName: string | null
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
clientCode: string
date: string | any
locationId: string
locationName: string
services: Array<{
id: string
serviceName: string
price: number
}>
payments: Array<{
id: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
}>
owed: number
paid: number
balance: number
}>
One of the requesting talent's own bookings β NOT_FOUND when it isn't theirs
{
appointmentId: string
}
{
id: string
scheduleId: string
startTime: string | null
clientName: string
menuLabel: string | null
fee: number
discount: number
confirmed: boolean
notes?: string | null
cancelledAt: string | any | null
bookerName: string | null
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
clientCode: string
date: string | any
locationId: string
locationName: string
services: Array<{
id: string
serviceName: string
price: number
}>
payments: Array<{
id: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
}>
owed: number
paid: number
balance: number
}
The requesting talent's own MonβSun pay week: services/extras/cancellation totals and the per-booking breakdown
{
date: any
}
{
startDate: string | any
endDate: string | any
services: number
extras: number
cancellations: number
total: number
rows: Array<{
appointmentId: string
date: string | any
clientCode: string
clientName: string
service: string
locationName: string
methods: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"[]
total: number
startTime: string | null
wrappedUpAt: string | any | null
}>
}
The requesting talent's own priced add-ons, for the wrap-up screen's chips
Array<{
menuServiceId: string
name: string
price: number
}>
Close out one of the requesting talent's own bookings: what she actually provided, the add-ons she sold and a private note for the office. Same-day or past only, once per booking, and never a pay change β a reported difference is flagged, not recalculated
{
appointmentId: string
today: any
noShow: boolean
extraMinutes: 0 | 15 | 30
extras: string[]
notes?: string
}
{
id: string
scheduleId: string
startTime: string | null
clientName: string
menuLabel: string | null
fee: number
discount: number
confirmed: boolean
notes?: string | null
cancelledAt: string | any | null
bookerName: string | null
isIndy: boolean
wrappedUpAt: string | any | null
wrapUpNoShow: boolean
wrapUpExtraMinutes: number
wrapUpNotes: string | null
wrapUpExtras: Array<{
menuServiceId: string
name: string
price: number
}>
clientCode: string
date: string | any
locationId: string
locationName: string
services: Array<{
id: string
serviceName: string
price: number
}>
payments: Array<{
id: string
method: "EMT" | "AmazonGiftCard" | "Cash" | "Credit" | "TalentCredit"
amount: number
isDeposit: boolean
}>
owed: number
paid: number
balance: number
}
Close out the requesting talent's own scheduled day β she declares the cash envelope handed in. Same-day or past only, once per day, and never a money change: the office sees the flag on the daily tracker
{
scheduleId: string
today: any
}
{
envelopeDroppedAt: string | any
}
Creates a new talent
{
nickname: string
age?: number | null
height?: string | null
weight?: string | null
measurements?: string | null
nationality?: string | null
hair?: string | null
eyes?: string | null
tattoos?: boolean | null
enhanced?: boolean | null
cupSize?: string | null
duos?: boolean | null
tagline?: string | null
bio?: string | null
badge?: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId?: string | null
phoneNumberExpiresAt?: any | null
notes?: string | null
tags?: string[]
menus?: Array<{
type: "Regular" | "Vip"
durationMinutes: number
price: number
}>
menuServices?: Array<{
serviceId: string
price?: number | null
}>
images?: Array<{
fileId: string
variant?: "Original" | "Thumbnail" | "Large"
imageBrand?: "LuxWatermark" | "Clean" | null
width?: number | null
height?: number | null
sortOrder?: number
}>
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
}
Updates an existing talent
{
nickname?: string
age?: number | null
height?: string | null
weight?: string | null
measurements?: string | null
nationality?: string | null
hair?: string | null
eyes?: string | null
tattoos?: boolean | null
enhanced?: boolean | null
cupSize?: string | null
duos?: boolean | null
tagline?: string | null
bio?: string | null
badge?: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId?: string | null
phoneNumberExpiresAt?: any | null
notes?: string | null
tags?: string[]
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
}
Deletes a talent
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
nickname: string
age: number | null
height: string | null
weight: string | null
measurements: string | null
nationality: string | null
hair: string | null
eyes: string | null
tattoos: boolean | null
enhanced: boolean | null
cupSize: string | null
duos: boolean | null
tagline: string | null
bio: string | null
badge: "Visiting" | "Star" | "Vip" | "New" | null
defaultPhoneNumberId: string | null
phoneNumberExpiresAt: string | any | null
}
Asks the office for a schedule change, a tour in one of the company cities, supplies for one of her own venues, an edit to her own profile or anything else. A request is a ticket β it never edits the schedule or the profile
{
type: "scheduleChange" | "profileChange" | "tour" | "supplies" | "other"
startDate?: "" | string
endDate?: "" | string
cityId?: string | null
locationId?: string | null
note?: string | null
}
{
id: string
createdAt: string | any
updatedAt: string | any
type: "timeOff" | "scheduleChange" | "profileChange" | "tour" | "supplies" | "other"
status: "open" | "approved" | "declined"
talentId: string | null
talentName: string
startDate: string | any | null
endDate: string | any | null
cityId: string | null
cityName: string | null
locationId: string | null
locationName: string | null
note: string | null
decisionNote: string | null
decidedAt: string | any | null
}
The requesting talent's own change requests, newest first, each with the office's answer once decided
Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "timeOff" | "scheduleChange" | "profileChange" | "tour" | "supplies" | "other"
status: "open" | "approved" | "declined"
talentId: string | null
talentName: string
startDate: string | any | null
endDate: string | any | null
cityId: string | null
cityName: string | null
locationId: string | null
locationName: string | null
note: string | null
decisionNote: string | null
decidedAt: string | any | null
}>
The days a tour ask would land over the city's capacity (LUX-271) β advisory only, the form shows it as a warning and the request always goes through
{
cityId: string
startDate: any
endDate: any
}
{
days: Array<{
date: string | any
scheduled: number
capacity: number
}>
}
Change requests from talent for the requesting company, newest first, optionally filtered by status
{
status?: "open" | "approved" | "declined"
}
Array<{
id: string
createdAt: string | any
updatedAt: string | any
type: "timeOff" | "scheduleChange" | "profileChange" | "tour" | "supplies" | "other"
status: "open" | "approved" | "declined"
talentId: string | null
talentName: string
startDate: string | any | null
endDate: string | any | null
cityId: string | null
cityName: string | null
locationId: string | null
locationName: string | null
note: string | null
decisionNote: string | null
decidedAt: string | any | null
}>
Approves or declines an open change request with an optional note. Approving does not touch the schedule β the office applies the change by hand
{
id: string
status: "approved" | "declined"
decisionNote?: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
type: "timeOff" | "scheduleChange" | "profileChange" | "tour" | "supplies" | "other"
status: "open" | "approved" | "declined"
talentId: string | null
talentName: string
startDate: string | any | null
endDate: string | any | null
cityId: string | null
cityName: string | null
locationId: string | null
locationName: string | null
note: string | null
decisionNote: string | null
decidedAt: string | any | null
}
User
Returns the authenticated user profile
{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
talentId?: string | null
seenTours: string[]
}
Updates the authenticated user profile (name, email) β the settings page. Role and phone are out of reach: role changes are admin-only, phone changes go through the SMS-verify flow.
{
email?: string
name?: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
talentId?: string | null
seenTours: string[]
}
Records an onboarding tour as seen so it never auto-starts again. A no-op while impersonating β standing in as someone must not mark their tours.
{
tourId: "welcome-admin" | "welcome-booker" | "notifications" | "complete-profile"
}
any
Creates a new user via the auth admin API
{
email: string
name: string
password: string
role: "user" | "admin" | "booker" | "talent" | "support"
payRate?: number | null
}
{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
talentId?: string | null
seenTours: string[]
}
Returns a user by their ID
{
id: string
}
{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
talentId?: string | null
seenTours: string[]
}
Updates an existing user
{
id: string
data: {
email?: string
name?: string
role?: "user" | "admin" | "booker" | "talent" | "support"
phoneNumber?: any | null
talentId?: string | null
}
}
{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
talentId?: string | null
seenTours: string[]
}
Sets a new password for a user via the auth admin API
{
userId: string
newPassword: string
}
Folds one user into another and deletes it: bookings, sent texts, payroll rows and uploads move to the survivor; overlapping weekly-payment receipts are summed. The retired login (sessions, passkeys) is destroyed. Irreversible.
{
keepUserId: string
mergeUserId: string
}
{
keptName: string
retiredName: string
appointmentsMoved: number
}
Returns all users
Array<{
id: string
createdAt: string | any
updatedAt: string | any
email: string
name: string | null
role: string | null
phoneNumber?: string | null
}>
WeeklyReport
Collected cash (by rail, per city), booker pay, and expenses (by category) rolled up over a week β the MonβSun bounds are sent by the client
{
startDate: any
endDate: any
}
{
weekStart: string | any
weekEnd: string | any
moneyIn: {
cash: number
emt: number
giftCard: number
credit: number
total: number
}
bookerPay: number
cancellationAgency: number
talentCredit: number
expensesByCategory: Record<string, number>
totalExpenses: number
generalExpenses: number
totalOut: number
net: number
cities: Array<{
city: string
moneyIn: {
cash: number
emt: number
giftCard: number
credit: number
total: number
}
bookerPay: number
cancellationAgency: number
talentCredit: number
expenses: number
}>
}