Bookings Staff Sorting Provider Service Plugin Reference
Overview
The Staff Sorting Provider SPI lets you implement custom staff assignment algorithms for Wix Bookings. When a booking slot has multiple available staff members, Wix calls your plugin to determine the priority order. Implement the sortStaffMembers handler — it returns the available staff members reordered by priority.
FQDN: wix.interfaces.resources.sorting.v1.staff_sorting_provider
Request and Response Schema
Before implementing, call ReadFullDocsMethodSchema on the docs URL to get the full request/response types.
| Handler | Docs URL |
|---|---|
sortStaffMembers |
https://dev.wix.com/docs/api-reference/business-solutions/bookings/staff-members/staff-sorting-service-plugin/sort-staff-members?apiView=SDK |
Important constraints:
- You must return the exact same IDs from
availableResourceIds, reordered by priority - Do not add or remove any IDs
- If your response is invalid, Wix falls back to random assignment
Performance Requirements
- Hard limit: Response must be returned within 5 seconds
- Recommended: Keep response time under 500ms for optimal user experience
Example: Workload Balancing
This example sorts staff members to balance workload by prioritizing those with fewer recent bookings.
import { staffSorting } from "@wix/bookings/service-plugins";
import { auth } from "@wix/essentials";
import { extendedBookings } from "@wix/bookings";
staffSorting.provideHandlers({
sortStaffMembers: async (payload) => {
const { request } = payload;
// availableResourceIds is optional on the request type — default it, or
// spreading/iterating it below fails `tsc` with "possibly undefined."
const { availableResourceIds = [], slot } = request;
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
const elevatedQuery = auth.elevate(extendedBookings.queryExtendedBookings);
const result = await elevatedQuery({
filter: {
"bookedEntity.item.slot.resource.id": { "$in": availableResourceIds },
"startDate": { "$gte": sevenDaysAgo },
},
cursorPaging: { limit: 100 },
});
const recentBookings = result.extendedBookings ?? [];
// Count bookings per staff member
const bookingCounts = new Map<string, number>();
for (const id of availableResourceIds) {
bookingCounts.set(id, 0);
}
for (const booking of recentBookings) {
const resourceId = booking.booking?.bookedEntity?.slot?.resource?._id;
if (resourceId && bookingCounts.has(resourceId)) {
bookingCounts.set(resourceId, (bookingCounts.get(resourceId) ?? 0) + 1);
}
}
// Sort by fewest bookings first (balance workload)
const sorted = [...availableResourceIds].sort(
(a, b) => (bookingCounts.get(a) ?? 0) - (bookingCounts.get(b) ?? 0)
);
return {
staff: sorted.map((resourceId) => ({ resourceId })),
};
},
});Manual Setup Required
None. Confirmed live with a service that has 2 assigned staff — the dashboard's "Add booking" flow resolved a specific staff member from the plugin's sorted order, and the booking created successfully with no errors. No dashboard configuration is needed beyond having the app installed and released, and the service having 2+ staff assigned to genuinely exercise the sort.
Key Implementation Notes
- Return all IDs - You must return every ID from
availableResourceIds, just reordered - Performance matters - Keep logic fast; the booking flow waits for your response
- Elevate permissions - Use
auth.elevatewhen querying Wix APIs from the handler - Deterministic sorting - Use a tiebreaker (e.g., resource ID) when priorities are equal
- Use
queryExtendedBookings, notquery—extendedBookings.queryis deprecated.queryExtendedBookingstakes the samefilter/cursorPagingshape, so it's a drop-in replacement; confirmed live after switching. availableResourceIdsis optional on the request type — default it to[]when destructuring, or spreading/iterating it failstscwith "possibly undefined."- Graceful degradation - If your external data source is unavailable, return the original order rather than failing