Availability Management¶
Complete guide to managing staff availability, schedules, and working hours in the Reserva platform.
Overview¶
The availability system provides comprehensive staff scheduling with support for:
- CRUD Operations - Create, read, update, delete availability entries
- Recurring Patterns - Daily, weekly, monthly schedules with smart expansion
- Bulk Creation - Efficiently create multiple varied schedule entries
- Conflict Detection - Smart type-based overlap prevention
- Working Hours Management - Regular hours, breaks, blocked time, vacation
- Real-time Checking - Instant availability verification for bookings
- Service-Specific Availability - Limit staff to specific services during time slots
Key Concepts:
- Working Hours = Staff available for appointments
- Break = Unavailable period within working hours (e.g., lunch)
- Blocked = Time reserved, no appointments allowed
- Vacation = Extended unavailability period
- Recurrence = Pattern-based schedule creation (daily/weekly/monthly)
- Bulk = Multiple varied entries in single request
Availability Types¶
The system supports four availability types with different conflict rules:
| Type | Description | Can Overlap With | Use Case |
|---|---|---|---|
| working_hours | Staff available for services | break | Regular shift: "9 AM - 5 PM" |
| break | Unavailable within working hours | working_hours | Lunch break: "12 PM - 1 PM" |
| blocked | Reserved time, no bookings | working_hours, break | Personal appointment, meeting |
| vacation | Extended absence | working_hours, break | Holiday, sick leave |
Smart Conflict Detection:
- ✅ BREAK can overlap with WORKING_HOURS - Breaks must be within work time
- ❌ WORKING_HOURS cannot overlap with other WORKING_HOURS - Prevents double scheduling
- ❌ BREAK cannot overlap with other BREAK - Each break must be distinct
- ✅ BLOCKED/VACATION can override WORKING_HOURS and BREAK - They take precedence and block time
- Example: 09:00-17:00 working + 10:00-12:00 vacation = ✅ Valid (vacation overrides)
- ❌ BLOCKED/VACATION cannot overlap with other BLOCKED/VACATION - Prevents duplicate blocks
List Staff Availability¶
Retrieve staff availability entries with date range and type filtering.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only view own availability
- TENANT_ADMIN/SUPER_ADMIN: Can view all staff availability
Query Parameters¶
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
start_date |
date | No | Start date for filtering (defaults to first day of current month) | 2025-01-15 |
end_date |
date | No | End date for filtering (defaults to last day of current month) | 2025-01-31 |
staff_id |
string | No | Filter by specific staff member | 507f1f77bcf86cd799439011 |
availability_type |
enum | No | Filter by type: working_hours, break, blocked, vacation |
working_hours |
outlet_id |
string | No | Filter by outlet | 507f1f77bcf86cd799439012 |
page |
integer | No | Page number (default: 1) | 1 |
size |
integer | No | Page size (default: 20, max: 100) | 20 |
Response¶
{
"items": [
{
"id": "507f1f77bcf86cd799439013",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "09:00:00",
"end_time": "17:00:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"recurrence_end_date": null,
"recurrence_days": null,
"is_available": true,
"notes": "Regular working day",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
},
{
"id": "507f1f77bcf86cd799439014",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "12:00:00",
"end_time": "13:00:00",
"availability_type": "break",
"recurrence_type": "none",
"is_available": false,
"notes": "Lunch break",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
}
],
"total": 2,
"page": 1,
"size": 20,
"pages": 1
}
Business Rules:
- Date range must be valid (start ≤ end)
- Staff users automatically limited to their own availability
- Defaults to current month if no dates specified
- Results sorted chronologically by date and start time
Note: service_ids: null means staff is available for ALL services they are qualified for during this time slot.
Create Staff Availability¶
Create new availability entry with automatic conflict detection and recurrence support.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only create own availability
- TENANT_ADMIN/SUPER_ADMIN: Can create any staff availability
Request Body¶
Single Entry (No Recurrence):
{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"is_available": true,
"notes": "Regular working day"
}
Daily Recurrence:
{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "daily",
"recurrence_end_date": "2025-01-31",
"is_available": true,
"notes": "Daily schedule for January"
}
Weekly Recurrence (Weekdays Only):
{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "weekly",
"recurrence_end_date": "2025-03-31",
"recurrence_days": [0, 1, 2, 3, 4],
"is_available": true,
"notes": "Monday to Friday working hours"
}
Monthly Recurrence:
{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "monthly",
"recurrence_end_date": "2025-12-15",
"is_available": true,
"notes": "15th of every month"
}
Service-Specific Availability:
{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "15:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"service_ids": ["507f1f77bcf86cd799439020"],
"notes": "Hair coloring services only today"
}
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
staff_id |
string | Yes | Staff member ID |
date |
date | Yes | Start date (YYYY-MM-DD) |
start_time |
time | Yes | Start time (HH:MM format) |
end_time |
time | Yes | End time (HH:MM format) |
availability_type |
enum | Yes | Type: working_hours, break, blocked, vacation |
recurrence_type |
enum | Yes | Pattern: none, daily, weekly, monthly |
recurrence_end_date |
date | Conditional | Required if recurrence_type != none |
recurrence_days |
array | No | Days for weekly (0=Mon, 1=Tue, ..., 6=Sun) |
is_available |
boolean | Yes | IMPORTANT: Must match type - true for working_hours, false for break/blocked/vacation |
notes |
string | No | Additional notes |
service_ids |
array | No | Service IDs (null = all services staff is qualified for) |
⚠️ Data Integrity Requirements:
The is_available flag MUST match the availability_type:
working_hours→ MUST haveis_available=truebreak→ MUST haveis_available=falseblocked→ MUST haveis_available=falsevacation→ MUST haveis_available=false
Validation will return 422 error if this rule is violated.
Response¶
Single Entry Response:
{
"id": "507f1f77bcf86cd799439013",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "09:00:00",
"end_time": "17:00:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"recurrence_end_date": null,
"recurrence_days": null,
"is_available": true,
"notes": "Regular working day",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
}
Recurring Entries Summary Response:
{
"message": "Successfully created recurring availability",
"summary": {
"total_entries_created": 15,
"date_range": {
"start": "2025-10-11",
"end": "2025-10-31"
},
"recurrence_pattern": {
"type": "weekly",
"days": ["Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
},
"staff_id": "507f1f77bcf86cd799439011",
"availability_type": "working_hours",
"time_range": "09:00 - 17:00"
},
"sample_entry": {
"id": "507f1f77bcf86cd799439013",
"date": "2025-10-11",
"start_time": "09:00:00",
"end_time": "17:00:00"
}
}
Business Rules:
- No overlapping time slots for same staff (with smart type-based detection)
- Working hours must be logical (start < end)
- Time must be in 5-minute increments (e.g., 09:00, 09:05, 09:10)
- Maximum 365 entries per recurring pattern
recurrence_end_dateREQUIRED for all recurring patterns (daily/weekly/monthly)recurrence_end_dateNOT required for single entries (recurrence_type: "none")
Recurrence Types:
- none: Single availability entry (no recurrence_end_date needed)
- daily: Repeats every day until end date (recurrence_end_date REQUIRED)
- weekly: Repeats weekly on specified days (recurrence_end_date REQUIRED, recurrence_days optional)
- monthly: Repeats monthly on same date (recurrence_end_date REQUIRED)
Why Summary Response for Recurring?
- Creating 100+ entries would return a massive JSON response
- Summary provides all necessary confirmation data
- Use GET /availability to retrieve specific entries afterward
- Improves API performance and usability
Important Notes on service_ids:
- Omit or set to null: Staff available for ALL services they are qualified for (most common)
- Provide specific IDs: Staff available ONLY for those services (e.g., ["coloring_id"] = coloring only)
- Use case: "Sarah does hair coloring on Wednesdays only, but all services other days"
Check Staff Availability¶
Verify staff availability for specific time slot with conflict details and parallel booking capacity.
Endpoint¶
Authentication: Required (JWT token)
Access Control: - STAFF/OUTLET_MANAGER: Can only check own availability - TENANT_ADMIN/SUPER_ADMIN: Can check any staff availability
Query Parameters¶
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
staff_id |
string | Yes | Staff member ID | 507f1f77bcf86cd799439011 |
date |
date | Yes | Date to check | 2025-01-15 |
start_time |
string | Yes | Start time (HH:MM format) | 14:30 |
end_time |
string | Yes | End time (HH:MM format) | 16:00 |
service_id |
string | No | Service ID for specific availability (enables capacity checking) | 507f1f77bcf86cd799439012 |
Response¶
Available:
{
"available": true,
"message": "Slot available",
"reason": null,
"working_hours": {
"start_time": "09:00:00",
"end_time": "17:00:00",
"breaks": [
{
"start": "12:00:00",
"end": "13:00:00"
}
]
},
"conflicts": []
}
Not Available (Staff Not Working):
{
"available": false,
"message": "Staff not working during this time",
"reason": "staff_not_working",
"working_hours": {
"start_time": "09:00:00",
"end_time": "17:00:00",
"breaks": []
},
"conflicts": []
}
Not Available (Booking Conflict):
{
"available": false,
"message": "Conflict detected",
"reason": "booking_conflict",
"working_hours": {
"start_time": "09:00:00",
"end_time": "17:00:00",
"breaks": [
{
"start": "12:00:00",
"end": "13:00:00"
}
]
},
"conflicts": [
{
"id": "507f1f77bcf86cd799439015",
"type": "blocked",
"start_time": "14:00:00",
"end_time": "15:00:00",
"notes": "Personal appointment"
}
]
}
Business Rules Applied:
- Staff working hours validation
- Smart appointment overlap detection:
- Single-booking services: Checks for ANY conflicting appointment
- Parallel-booking services: Checks current bookings vs max capacity
- Returns capacity information when
service_idprovided - Break period consideration
- Service-specific availability rules
Parallel Booking Capacity Checking:
- When
service_idis provided, system checks service-specific capacity -
Services with
allow_parallel_bookings=Truetrack current vs max capacity -
Examples:
-
Group Yoga (7/10 bookings): Returns
available=truewith capacity info - Group Yoga (10/10 bookings): Returns
available=false(capacity reached) - Haircut (1/1 booking): Returns
available=false(traditional behavior) -
When
service_idis NOT provided, performs generic overlap check -
Backward compatible: Single-booking services work exactly as before
Use Cases:
- Pre-appointment booking validation
- Schedule conflict prevention
- Booking system integration
- Real-time schedule checking
- Group service capacity verification
Note: Essential for appointment booking systems to prevent double-booking or capacity overrun.
Related Documentation: See Parallel Booking for capacity management details.
Get Multi-Day Availability Grid¶
Retrieve availability grid showing available time slots across multiple days for staff schedule management.
Endpoint¶
Authentication: Required (JWT token)
Access Control: - STAFF: Can view own availability grid - OUTLET_MANAGER/TENANT_ADMIN/SUPER_ADMIN: Can view any staff availability grid
Query Parameters¶
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
service_id |
string | Yes | Service ID to check availability for | 507f1f77bcf86cd799439013 |
outlet_id |
string | Yes | Outlet ID where service will be performed | 507f1f77bcf86cd799439012 |
start_date |
date | Yes | First date to check (YYYY-MM-DD) | 2025-10-03 |
num_days |
integer | No | Number of days to retrieve (1-90, default: 7) | 7 |
slot_interval_minutes |
integer | No | Slot interval in minutes (default: 30) | 30 |
staff_id |
string | No | Optional specific staff member filter | 507f1f77bcf86cd799439014 |
Response¶
{
"start_date": "2025-10-03",
"end_date": "2025-10-09",
"num_days": 7,
"slot_interval_minutes": 30,
"availability_grid": {
"2025-10-03": [
{
"start_time": "09:00",
"end_time": "09:30",
"staff_id": "507f1f77bcf86cd799439014",
"gender": "female",
"is_available": true,
"allows_parallel_bookings": false,
"available_capacity": null,
"max_capacity": null
},
{
"start_time": "10:00",
"end_time": "11:00",
"staff_id": "507f1f77bcf86cd799439015",
"gender": "male",
"is_available": true,
"allows_parallel_bookings": true,
"available_capacity": 7,
"max_capacity": 10
}
],
"2025-10-04": [],
"2025-10-05": [
{
"start_time": "14:00",
"end_time": "15:00",
"staff_id": "507f1f77bcf86cd799439014",
"gender": "female",
"is_available": true,
"allows_parallel_bookings": true,
"available_capacity": 5,
"max_capacity": 12
}
]
},
"metadata": {
"service_id": "507f1f77bcf86cd799439013",
"service_name": "Haircut",
"outlet_id": "507f1f77bcf86cd799439012",
"outlet_name": "Downtown Salon",
"staff_id": null,
"total_available_slots": 42,
"service_duration_minutes": 90
}
}
Response Fields¶
Grid Structure:
- availability_grid: Date-keyed dictionary with arrays of available time slots
- Empty arrays indicate outlet closed or no staff available that day
- Missing slots indicate those times are unavailable/booked
Slot Fields:
| Field | Type | Description |
|---|---|---|
start_time |
string | Slot start time (HH:MM format) |
end_time |
string | Slot end time (HH:MM format) |
staff_id |
string | Staff member ID for this slot |
gender |
string|null | Staff member's gender (male, female, other, prefer_not_to_say) for service matching |
is_available |
boolean | Whether slot is available for booking |
allows_parallel_bookings |
boolean | Whether service supports multiple simultaneous bookings |
available_capacity |
integer|null | Remaining spots (null for single-booking services) |
max_capacity |
integer|null | Total capacity (null for single-booking services) |
Metadata Fields:
- Service and outlet information
- Total available slot count across all days
- Service duration for context
- Staff filter applied (if any)
Features¶
- Multi-day calendar view for better schedule management
- Efficient single API call instead of N calls for N days
- Shows only available slots (missing slots = unavailable/booked)
- Configurable slot intervals (15, 30, 60, 120 minutes)
- Optional staff filtering for team coordination
- Parallel booking capacity display - shows remaining spots for group services
Business Rules Applied¶
- Date validation: start_date can be in the past for staff (schedule review)
- Booking window: Limited to 90 days maximum (staff need longer view than customers)
- Outlet business hours: Respects daily operating hours
- Staff availability: Validates working hours and breaks
- Smart conflict detection:
- Single-booking services: Slot hidden if booked
- Parallel-booking services: Slot shows remaining capacity
- Service duration: Calculates end times based on service length
Parallel Booking Capacity Information¶
Each slot includes capacity fields for group service management:
- allows_parallel_bookings: Boolean indicating if service supports multiple bookings
- available_capacity: Remaining spots (e.g., 7 means "7 spots left")
- max_capacity: Total capacity (e.g., 10)
Example Slot for Group Service:
{
"start_time": "14:00",
"end_time": "15:00",
"staff_id": "507f1f77bcf86cd799439014",
"gender": "female",
"is_available": true,
"allows_parallel_bookings": true,
"available_capacity": 5,
"max_capacity": 12
}
Staff Portal Display Examples¶
- Group Fitness Class (5/12 spots left): Show "5 available" with booking capacity indicator
- Almost Full (1/12 spots left): Highlight urgency for staff to promote
- Full (0/12 spots): Show "Fully Booked" status
- Single-booking service: No capacity info, traditional display
Frontend Usage Example¶
const grid = await fetch('/api/v1/staff/availability/availability-grid?...');
// Iterate through dates
Object.entries(grid.availability_grid).forEach(([date, slots]) => {
if (slots.length === 0) {
// Day unavailable - show as disabled
disableDate(date);
} else {
// Show available time slots with capacity and gender info
slots.forEach(slot => {
if (slot.allows_parallel_bookings) {
// Group service - show capacity for staff awareness
renderSlot(slot, {
capacity: `${slot.available_capacity}/${slot.max_capacity}`,
urgency: slot.available_capacity <= 2 ? 'high' : 'normal',
gender: slot.gender // For gender-specific service filtering
});
} else {
// Single-booking service - traditional display with gender
renderSlot(slot, { gender: slot.gender });
}
});
}
});
Gender Field Use Cases:
- Massage therapy: Filter by staff gender for customer comfort
- Waxing services: Allow customers to choose preferred staff gender
- Personal care: Enable gender-preference filtering in booking UI
Use Cases¶
- Staff schedule review and planning
- Multi-day calendar view for booking coordination
- Team availability coordination
- Past schedule review (staff can view historical data)
- Group service capacity monitoring
- Frontend calendar/time-picker integration
Error Responses¶
400 Bad Request - Invalid Parameters:
403 Forbidden - Access Denied:
404 Not Found - Service/Outlet Not Found:
Note: This endpoint is optimized for calendar/time-picker UIs and staff schedule management.
Related Documentation: See Parallel Booking for capacity management details.
Get Availability Entry¶
Retrieve complete details for a specific availability entry.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only view own entries
- TENANT_ADMIN/SUPER_ADMIN: Can view any entries
Response¶
{
"id": "507f1f77bcf86cd799439013",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "09:00:00",
"end_time": "17:00:00",
"availability_type": "working_hours",
"recurrence_type": "weekly",
"recurrence_end_date": "2025-03-31",
"recurrence_days": [0, 1, 2, 3, 4],
"is_available": true,
"notes": "Monday to Friday working hours",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
}
Business Rules:
- Entry must exist and belong to user's tenant
- Staff users limited to their own entries
- Proper ObjectId format validation
Update Availability Entry¶
Update existing availability entry with conflict detection and validation.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only update own entries
- TENANT_ADMIN/SUPER_ADMIN: Can update any entries
Request Body¶
Parameters: All fields are optional (partial updates supported)
| Field | Type | Description |
|---|---|---|
date |
date | Update date (YYYY-MM-DD) |
start_time |
time | Update start time (HH:MM) |
end_time |
time | Update end time (HH:MM) |
availability_type |
enum | Update type |
is_available |
boolean | Update availability flag |
notes |
string | Update notes |
service_ids |
array | Update service restrictions |
Response¶
{
"id": "507f1f77bcf86cd799439013",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "10:00:00",
"end_time": "18:00:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"is_available": true,
"notes": "Updated schedule - later shift",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-15T14:30:00Z"
}
Business Rules:
- Entry must exist and belong to user's tenant
- No conflicting time slots after update
- Time ranges must be logical (start < end)
- Staff users limited to their own entries
Note: Conflicts with existing schedules will prevent updates.
Delete Availability Entry¶
Remove availability entry from staff schedule (soft delete for audit trail).
Endpoint¶
Authentication: Required (JWT token)
Access Control: - STAFF/OUTLET_MANAGER: Can only delete own entries - TENANT_ADMIN/SUPER_ADMIN: Can delete any entries
Response¶
Business Rules:
- Entry must exist and belong to user's tenant
- Staff users limited to their own entries
- Soft delete maintains audit trail
- Consider impact on scheduled appointments
Note: Deleted entries are hidden but preserved for audit purposes.
Create Bulk Availability¶
Create multiple availability entries with different configurations in a single request.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only create own bulk schedules
- TENANT_ADMIN/SUPER_ADMIN: Can create any bulk schedules
When to Use This Endpoint¶
Key Difference from Recurrence Endpoint:
- This endpoint: Creates entries from a list of varied specifications (different dates, times, types)
- POST /availability with recurrence: Creates entries from a single pattern (same time, recurring schedule)
Use This Endpoint For:
- ✅ Non-uniform schedules: Different times on different days (Mon 9-5, Tue 10-6, Wed 9-3)
- ✅ Mixed entry types: Combining working hours + breaks + blocked time in one request
- ✅ Schedule templates: Applying pre-defined weekly templates with varied configurations
- ✅ Import operations: Bulk importing schedules from external systems or spreadsheets
- ✅ Complex patterns: Schedules that can't be expressed as simple daily/weekly/monthly recurrence
Use POST /availability Instead For:
- ❌ Uniform recurring pattern (same time every day/week/month)
- ❌ Simple "Mon-Fri 9-5" type schedules
- ❌ Single entry creation
Request Body¶
{
"staff_id": "507f1f77bcf86cd799439011",
"availability_entries": [
{
"date": "2025-01-13",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "none"
},
{
"date": "2025-01-13",
"start_time": "12:00",
"end_time": "13:00",
"availability_type": "break",
"is_available": false,
"recurrence_type": "none"
},
{
"date": "2025-01-14",
"start_time": "10:00",
"end_time": "18:00",
"availability_type": "working_hours",
"recurrence_type": "none"
},
{
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "15:00",
"availability_type": "working_hours",
"service_ids": ["507f1f77bcf86cd799439020"],
"notes": "Coloring services only today",
"recurrence_type": "none"
}
]
}
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
staff_id |
string | Yes | Staff member ID for all entries |
availability_entries |
array | Yes | List of availability specifications (max 50) |
Each Entry in Array:
| Field | Type | Required | Description |
|---|---|---|---|
date |
date | Yes | Entry date (YYYY-MM-DD) |
start_time |
time | Yes | Start time (HH:MM) |
end_time |
time | Yes | End time (HH:MM) |
availability_type |
enum | Yes | Type: working_hours, break, blocked, vacation |
recurrence_type |
enum | Yes | Pattern: none (most common for bulk) |
is_available |
boolean | No | Availability flag |
notes |
string | No | Entry notes |
service_ids |
array | No | Service restrictions |
Response¶
{
"message": "Successfully created bulk availability",
"summary": {
"total_entries_created": 4,
"date_range": {
"start": "2025-01-13",
"end": "2025-01-15"
},
"staff_id": "507f1f77bcf86cd799439011",
"entry_types": ["working_hours", "break"],
"unique_dates": 3
},
"sample_entry": {
"id": "507f1f77bcf86cd799439013",
"date": "2025-01-13",
"start_time": "09:00:00",
"end_time": "17:00:00"
}
}
Business Rules:
- All entries must pass individual validation
- No conflicts between entries in the same batch
- Rollback entire operation if any entry fails
- Maximum 50 entries per request (rate limiting)
Smart Conflict Detection:
- BREAK can overlap with WORKING_HOURS: Breaks are allowed within work time
- Example: 09:00-17:00 working + 12:00-13:00 break = ✅ Valid
- WORKING_HOURS cannot overlap with other WORKING_HOURS: Prevents double scheduling
- BREAK cannot overlap with other BREAK: Each break must be distinct
- BLOCKED/VACATION can override WORKING_HOURS and BREAK: They take precedence and block time
- Example: 09:00-17:00 working + 10:00-12:00 vacation = ✅ Valid (vacation overrides)
- BLOCKED/VACATION cannot overlap with other BLOCKED/VACATION: Prevents duplicate blocks
Why Summary Response?
- Creating 50 entries would return a massive JSON response
- Summary provides all necessary confirmation data
- Use GET /availability to retrieve specific entries afterward
- Improves API performance and usability
Note: Operation fails entirely if any entry has conflicts or validation errors.
Get Staff Schedule¶
Retrieve complete staff schedule for specified date range.
Endpoint¶
Authentication: Required (JWT token)
Access Control:
- STAFF/OUTLET_MANAGER: Can only view own schedules
- TENANT_ADMIN/SUPER_ADMIN: Can view any staff schedules
Query Parameters¶
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
start_date |
date | Yes | Start date for range | 2025-01-15 |
end_date |
date | Yes | End date for range | 2025-01-31 |
include_breaks |
boolean | No | Include break periods (default: true) | true |
Response¶
[
{
"id": "507f1f77bcf86cd799439013",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "09:00:00",
"end_time": "17:00:00",
"availability_type": "working_hours",
"recurrence_type": "none",
"is_available": true,
"notes": "Regular working day",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
},
{
"id": "507f1f77bcf86cd799439014",
"staff_id": "507f1f77bcf86cd799439011",
"outlet_id": "507f1f77bcf86cd799439012",
"date": "2025-01-15",
"start_time": "12:00:00",
"end_time": "13:00:00",
"availability_type": "break",
"recurrence_type": "none",
"is_available": false,
"notes": "Lunch break",
"service_ids": null,
"created_at": "2025-01-10T08:00:00Z",
"updated_at": "2025-01-10T08:00:00Z"
}
]
Business Rules:
- Date range must be valid (start ≤ end)
- Staff users limited to their own availability
- Results include all availability types unless filtered
Use Cases:
- Staff schedule review and planning
- Appointment booking availability checks
- Schedule conflict identification
- Reporting and analytics
Subscription Plan Limits¶
Availability management is subject to subscription plan limits:
| Plan | Max Staff per Outlet | Appointments per Month | Notes |
|---|---|---|---|
| FREE | 5 | 100 | Limited to 1 outlet |
| PRO | 50 | 2,000 | Up to 10 outlets |
| ENTERPRISE | Unlimited | Unlimited | Unlimited outlets |
How Limits Apply:
- Staff Count: Number of active staff members per outlet affects availability entries
- Appointment Limits: Availability schedules must accommodate monthly appointment quotas
- Outlets: Multi-outlet businesses need appropriate plans
Upgrade Recommendation:
If you're hitting limits, consider upgrading:
See Subscription Management for details.
Business Rules Summary¶
Time Validation¶
- Start time must be before end time
- Time must be in 5-minute increments (09:00, 09:05, 09:10)
- Date range must be valid (start ≤ end)
- Maximum 365 entries per recurring pattern
Conflict Prevention¶
Type-Based Conflict Matrix:
| working_hours | break | blocked | vacation | |
|---|---|---|---|---|
| working_hours | ❌ Conflict | ✅ Allowed | ✅ Overridden | ✅ Overridden |
| break | ✅ Allowed | ❌ Conflict | ✅ Overridden | ✅ Overridden |
| blocked | ✅ Override | ✅ Override | ❌ Conflict | ❌ Conflict |
| vacation | ✅ Override | ✅ Override | ❌ Conflict | ❌ Conflict |
Smart Logic:
- Breaks MUST overlap with working hours (breaks happen during work)
- Working hours cannot overlap with other working hours
- Blocked/vacation can override working hours and breaks (they take precedence and block time)
- Blocked/vacation cannot overlap with other blocked/vacation periods
Access Control¶
| Role | List All | List Own | Create | Update | Delete |
|---|---|---|---|---|---|
| STAFF | ❌ | ✅ | ✅ (own) | ✅ (own) | ✅ (own) |
| OUTLET_MANAGER | ❌ | ✅ | ✅ (own) | ✅ (own) | ✅ (own) |
| TENANT_ADMIN | ✅ | ✅ | ✅ (all) | ✅ (all) | ✅ (all) |
| SUPER_ADMIN | ✅ | ✅ | ✅ (all) | ✅ (all) | ✅ (all) |
Recurrence Requirements¶
| Recurrence Type | recurrence_end_date | recurrence_days | Max Entries |
|---|---|---|---|
| none | ❌ Not required | ❌ Not used | 1 |
| daily | ✅ Required | ❌ Not used | 365 |
| weekly | ✅ Required | Optional (all days if omitted) | 365 |
| monthly | ✅ Required | ❌ Not used | 365 |
Common Use Cases¶
1. Set Regular Working Hours (Mon-Fri, 9-5)¶
curl -X POST https://api.myreserva.id/api/v1/availability \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-13",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "weekly",
"recurrence_end_date": "2025-12-31",
"recurrence_days": [0, 1, 2, 3, 4],
"notes": "Regular weekday hours"
}'
2. Add Daily Lunch Break¶
curl -X POST https://api.myreserva.id/api/v1/availability \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-13",
"start_time": "12:00",
"end_time": "13:00",
"availability_type": "break",
"recurrence_type": "weekly",
"recurrence_end_date": "2025-12-31",
"recurrence_days": [0, 1, 2, 3, 4],
"is_available": false,
"notes": "Daily lunch break"
}'
3. Block Time for Personal Appointment¶
curl -X POST https://api.myreserva.id/api/v1/availability \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-01-20",
"start_time": "14:00",
"end_time": "15:30",
"availability_type": "blocked",
"recurrence_type": "none",
"is_available": false,
"notes": "Doctor appointment"
}'
Note: Blocked time can override existing working hours. If staff has working hours from 09:00-17:00, creating this blocked entry will mark 14:00-15:30 as unavailable for bookings, even though it overlaps with working hours.
4. Schedule Vacation¶
curl -X POST https://api.myreserva.id/api/v1/availability \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staff_id": "507f1f77bcf86cd799439011",
"date": "2025-07-01",
"start_time": "00:00",
"end_time": "23:59",
"availability_type": "vacation",
"recurrence_type": "daily",
"recurrence_end_date": "2025-07-14",
"is_available": false,
"notes": "Summer vacation"
}'
Note: Vacation time automatically overrides any existing working hours or breaks. You don't need to delete working hours first - the vacation entry will take precedence and block all appointment bookings during this period.
5. Create Non-Uniform Weekly Schedule (Bulk)¶
curl -X POST https://api.myreserva.id/api/v1/availability/bulk \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staff_id": "507f1f77bcf86cd799439011",
"availability_entries": [
{
"date": "2025-01-13",
"start_time": "09:00",
"end_time": "17:00",
"availability_type": "working_hours",
"recurrence_type": "none"
},
{
"date": "2025-01-14",
"start_time": "10:00",
"end_time": "18:00",
"availability_type": "working_hours",
"recurrence_type": "none"
},
{
"date": "2025-01-15",
"start_time": "09:00",
"end_time": "15:00",
"availability_type": "working_hours",
"recurrence_type": "none"
}
]
}'
6. Check Availability Before Booking¶
curl -X GET "https://api.myreserva.id/api/v1/availability/check?staff_id=507f1f77bcf86cd799439011&date=2025-01-15&start_time=14:30&end_time=16:00" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Error Handling¶
Common Error Responses¶
409 Conflict - Schedule Conflict Detected:
422 Unprocessable Entity - Validation Error:
403 Forbidden - Insufficient Permissions:
404 Not Found - Entry Not Found:
Integration with Other Features¶
Appointment Booking¶
Availability management integrates with the appointment system:
- Pre-Booking Validation - Use
/availability/checkto verify staff availability - Booking Creation - Appointment system respects availability schedules
- Conflict Prevention - Appointments cannot be booked during breaks, blocked time, or vacation
- Working Hours - Appointments must fall within staff working hours
See Appointment Management (coming soon) for details.
Staff Management¶
Staff profiles link to availability:
- Service Assignments - Availability can be restricted to specific services
- Outlet Assignments - Staff availability is outlet-specific
- Skills & Qualifications - Service restrictions respect staff skills
See Staff Management for details.
Service Management¶
Service catalog integration:
- Service-Specific Availability - Limit staff to certain services during time slots
- Duration Validation - Appointments respect service durations
- Pricing Context - Availability doesn't affect pricing but enables bookings
See Service Management for details.
Best Practices¶
For Regular Schedules¶
✅ DO:
- Use weekly recurrence for consistent Mon-Fri schedules
- Set breaks within working hours (breaks overlap with work)
- Plan availability at least 2 weeks in advance
- Use meaningful notes for context
❌ DON'T:
- Create individual entries for recurring patterns (use recurrence)
- Overlap working hours with other working hours
- Set breaks outside working hours
- Exceed 365 entries per recurrence pattern
For Complex Schedules¶
✅ DO:
- Use bulk endpoint for varied weekly templates
- Combine working hours + breaks in bulk requests
- Import schedules from external systems via bulk
- Verify conflicts before bulk creation
❌ DON'T:
- Use recurrence for non-uniform schedules (use bulk)
- Send more than 50 entries per bulk request
- Skip conflict validation
- Ignore response summaries
For Real-Time Booking¶
✅ DO:
- Always use
/availability/checkbefore creating appointments - Cache working hours for performance
- Handle conflicts gracefully with alternative suggestions
- Respect break periods
❌ DON'T:
- Create appointments without availability validation
- Assume staff is always available
- Ignore break periods
- Skip service-specific availability rules
API Reference Summary¶
| Endpoint | Method | Purpose | Response Type |
|---|---|---|---|
/availability |
GET | List availability entries with filters | Paginated list |
/availability |
POST | Create single/recurring entry | Single entry or summary |
/availability/check |
GET | Verify staff availability for slot (with capacity) | Availability status |
/availability/availability-grid |
GET | Get multi-day availability grid with capacity | Grid structure |
/availability/{id} |
GET | Get specific entry details | Single entry |
/availability/{id} |
PUT | Update existing entry | Updated entry |
/availability/{id} |
DELETE | Remove entry (soft delete) | Success message |
/availability/bulk |
POST | Create multiple varied entries | Summary response |
/availability/staff/{id} |
GET | Get complete staff schedule | Entry list |
Related Documentation:
- Staff Management - Staff profiles and working hours
- Service Management - Service configuration
- Outlet Management - Outlet operating hours
- Parallel Booking - Group services and capacity management
- Appointment Management - Appointment booking integration
- Subscription Management - Plan limits
Next Steps:
- Review subscription limits: Subscription Management
- Understand staff context: Staff Management
- Set up outlets: Outlet Management
- Configure services: Service Management
- Integrate with appointments: Appointment Management (coming soon)
For interactive testing, use the Swagger UI or ReDoc.