This endpoint requires a valid JWT Bearer token. Accessible via the API gateway at /v1/commerce/*.
Seating Optimization API
Intelligent table assignment, wait time estimation, turn time prediction, and seating analytics powered by AI.
All endpoints require a valid Bearer token. See Authentication for details.
Overview
| Attribute | Value |
|---|---|
| Base Path | /api/v1/seating |
| Authentication | Bearer Token |
| Required Roles | pos_staff, host, server, bartender, cashier, chef, kitchen, manager, restaurant_manager, tenant_admin, platform_admin, system_admin, super_admin |
Table Assignment
The seating engine uses machine learning to optimize table assignments based on party size, customer history, reservation patterns, and real-time floor status. Confidence scores above 0.85 indicate a strong match. Always review the reasoning.factors_considered field to understand assignment logic.
Get Optimal Assignment
Get AI-recommended table assignment for a party.
POST /api/v1/seating/assign
Request Body
{
"location_id": "loc_123",
"party_size": 4,
"preferences": {
"seating_area": "patio",
"accessibility": false,
"booth_preferred": true,
"quiet_area": false
},
"reservation_id": "res_456",
"customer_id": "cust_789"
}
Response
{
"recommendation": {
"table_id": "table_12",
"table_name": "Patio 12",
"capacity": 4,
"area": "patio",
"type": "booth",
"confidence": 0.92
},
"alternatives": [
{
"table_id": "table_14",
"table_name": "Patio 14",
"capacity": 6,
"area": "patio",
"type": "table",
"confidence": 0.85,
"note": "Larger table, may affect turn time"
},
{
"table_id": "table_08",
"table_name": "Indoor 8",
"capacity": 4,
"area": "main",
"type": "booth",
"confidence": 0.78,
"note": "Indoor option if patio unavailable"
}
],
"reasoning": {
"factors_considered": [
"Party size match",
"Preference for patio seating",
"Preference for booth",
"Customer history (prefers window view)",
"Current table availability",
"Expected turn time optimization"
],
"customer_insights": {
"visit_count": 12,
"usual_table_preference": "patio",
"avg_party_size": 3.5,
"avg_spend": 145.00
}
}
}
Confirm Assignment
Confirm a table assignment.
POST /api/v1/seating/assign/confirm
Request Body
{
"location_id": "loc_123",
"table_id": "table_12",
"party_size": 4,
"reservation_id": "res_456",
"notes": "Window seat requested"
}
Response
{
"assignment_id": "assign_001",
"table_id": "table_12",
"status": "seated",
"seated_at": "2026-01-24T19:30:00Z",
"predicted_clear_time": "2026-01-24T21:00:00Z",
"server_assigned": {
"id": "emp_001",
"name": "Sarah"
}
}
Turn Time Prediction
Predict Turn Time
Predict how long a table will be occupied.
POST /api/v1/seating/turn-time/predict
Request Body
{
"location_id": "loc_123",
"table_id": "table_12",
"party_size": 4,
"meal_period": "dinner",
"day_of_week": "saturday",
"reservation_type": "special_occasion",
"customer_id": "cust_789"
}
Response
{
"prediction": {
"expected_duration_minutes": 95,
"range": {
"min_minutes": 75,
"max_minutes": 120
},
"confidence": 0.85
},
"factors": [
{
"factor": "party_size",
"impact": "+10 min",
"detail": "4-top averages 10 min longer than 2-top"
},
{
"factor": "day_of_week",
"impact": "+15 min",
"detail": "Saturday dinners run 15% longer"
},
{
"factor": "reservation_type",
"impact": "+20 min",
"detail": "Special occasions tend to linger"
},
{
"factor": "customer_history",
"impact": "-5 min",
"detail": "This customer typically dines efficiently"
}
],
"historical_comparison": {
"similar_parties_avg_minutes": 92,
"this_table_avg_minutes": 88,
"this_time_slot_avg_minutes": 95
}
}
Get Turn Time Analytics
GET /api/v1/seating/turn-time/analytics
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
period | string | today, week, month |
area | string | Filter by seating area |
Response
{
"location_id": "loc_123",
"period": "week",
"summary": {
"avg_turn_time_minutes": 72,
"target_turn_time_minutes": 65,
"total_turns": 845,
"turns_per_table_avg": 4.2
},
"by_meal_period": [
{
"period": "lunch",
"avg_minutes": 48,
"turns": 320,
"target": 45
},
{
"period": "dinner",
"avg_minutes": 88,
"turns": 525,
"target": 75
}
],
"by_party_size": [
{"size": 2, "avg_minutes": 62},
{"size": 4, "avg_minutes": 78},
{"size": 6, "avg_minutes": 95}
],
"by_day": [
{"day": "monday", "avg_minutes": 65},
{"day": "friday", "avg_minutes": 82},
{"day": "saturday", "avg_minutes": 92}
],
"improvement_opportunities": [
{
"area": "dessert_timing",
"potential_savings_minutes": 8,
"suggestion": "Proactive dessert menu presentation"
},
{
"area": "check_delivery",
"potential_savings_minutes": 5,
"suggestion": "Offer check with dessert on busy nights"
}
]
}
Wait Time Estimation
Estimate Wait Time
Get accurate wait time estimate for walk-ins.
POST /api/v1/seating/wait-time/estimate
Request Body
{
"location_id": "loc_123",
"party_size": 4,
"preferences": {
"seating_area": "any",
"willing_to_split": false
}
}
Response
{
"estimate": {
"wait_time_minutes": 25,
"range": {
"min_minutes": 15,
"max_minutes": 40
},
"confidence": 0.82
},
"position_in_queue": 3,
"parties_ahead": [
{"size": 2, "wait_time_remaining_minutes": 5},
{"size": 6, "wait_time_remaining_minutes": 15},
{"size": 4, "wait_time_remaining_minutes": 20}
],
"available_tables": {
"matching_4_top": 0,
"larger_available": 1,
"note": "6-top available now if willing to take larger table"
},
"expected_turnover": [
{"table_id": "table_05", "size": 4, "expected_available_minutes": 15},
{"table_id": "table_12", "size": 4, "expected_available_minutes": 25}
],
"alternatives": {
"bar_seating": {
"available": true,
"wait_minutes": 0,
"note": "Immediate bar seating for 4"
},
"patio_different": {
"wait_minutes": 10,
"note": "High-top on patio in 10 minutes"
}
}
}
Add to Waitlist
POST /api/v1/seating/waitlist
Request Body
{
"location_id": "loc_123",
"party_size": 4,
"customer_name": "Smith",
"phone": "+15551234567",
"preferences": {
"seating_area": "patio",
"notifications": "sms"
},
"quoted_wait_minutes": 25
}
Response
{
"waitlist_id": "wait_001",
"position": 4,
"estimated_wait_minutes": 25,
"notification_method": "sms",
"confirmation_sent": true,
"tracking_url": "https://wait.example.com/w/wait_001"
}
Get Waitlist
GET /api/v1/seating/waitlist
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
status | string | waiting, notified, seated, removed |
Update Waitlist Entry
PATCH /api/v1/seating/waitlist/{waitlist_id}
Request Body
{
"status": "notified",
"notification_sent_at": "2026-01-24T19:55:00Z"
}
RevPASH Analytics
Calculate RevPASH
Calculate Revenue Per Available Seat Hour.
POST /api/v1/seating/revpash/calculate
Request Body
{
"location_id": "loc_123",
"period": {
"start": "2026-01-24T11:00:00Z",
"end": "2026-01-24T22:00:00Z"
}
}
Response
{
"revpash": {
"value": 28.50,
"currency": "USD",
"unit": "per_seat_hour"
},
"components": {
"total_revenue": 12540.00,
"total_seats": 80,
"operating_hours": 11,
"seat_hours_available": 880,
"seat_hours_utilized": 612,
"utilization_rate": 0.695
},
"by_hour": [
{"hour": "11:00", "revpash": 15.20, "utilization": 0.45},
{"hour": "12:00", "revpash": 42.80, "utilization": 0.92},
{"hour": "13:00", "revpash": 38.50, "utilization": 0.88},
{"hour": "18:00", "revpash": 52.30, "utilization": 0.98},
{"hour": "19:00", "revpash": 55.00, "utilization": 1.00}
],
"by_area": [
{"area": "main", "revpash": 32.40, "seats": 50},
{"area": "patio", "revpash": 28.80, "seats": 20},
{"area": "bar", "revpash": 18.50, "seats": 10}
],
"comparison": {
"vs_yesterday": 5.2,
"vs_last_week": -2.1,
"vs_target": 8.5
},
"optimization_opportunities": [
{
"opportunity": "off_peak_promotion",
"potential_increase": 12,
"detail": "3-5pm shows 40% seat utilization - consider happy hour promo"
},
{
"opportunity": "turn_time_improvement",
"potential_increase": 8,
"detail": "Reducing average turn time by 10 min could add 1 extra turn"
}
]
}
Get RevPASH Report
GET /api/v1/seating/revpash/report
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
start_date | date | Period start |
end_date | date | Period end |
granularity | string | hour, day, week |
No-Show Prediction
Predict No-Show Probability
POST /api/v1/seating/no-show/predict
Request Body
{
"reservation_id": "res_456",
"customer_id": "cust_789",
"party_size": 6,
"reservation_time": "2026-01-25T19:00:00Z",
"booking_lead_time_hours": 72
}
Response
{
"reservation_id": "res_456",
"no_show_probability": 0.15,
"risk_level": "moderate",
"factors": [
{
"factor": "party_size",
"impact": "+5%",
"detail": "Larger parties (6+) have higher no-show rate"
},
{
"factor": "lead_time",
"impact": "+3%",
"detail": "Bookings 72+ hours out have higher no-show rate"
},
{
"factor": "customer_history",
"impact": "-8%",
"detail": "Customer has 0 no-shows in 12 visits"
},
{
"factor": "day_of_week",
"impact": "+2%",
"detail": "Saturday nights have slightly higher no-show rate"
}
],
"recommendations": [
{
"action": "confirmation_call",
"timing": "24 hours before",
"reason": "Large party with moderate risk"
},
{
"action": "overbook_slight",
"detail": "Consider accepting 1 additional 2-top reservation"
}
],
"historical_stats": {
"similar_reservations_no_show_rate": 0.12,
"location_avg_no_show_rate": 0.08,
"this_customer_no_show_rate": 0.00
}
}
Get No-Show Analytics
GET /api/v1/seating/no-show/analytics
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
period | string | week, month, quarter |
Response
{
"location_id": "loc_123",
"period": "month",
"summary": {
"total_reservations": 1250,
"no_shows": 85,
"no_show_rate": 0.068,
"estimated_lost_revenue": 12750.00
},
"by_party_size": [
{"size": "1-2", "no_show_rate": 0.04},
{"size": "3-4", "no_show_rate": 0.06},
{"size": "5-6", "no_show_rate": 0.09},
{"size": "7+", "no_show_rate": 0.14}
],
"by_day_of_week": [
{"day": "friday", "no_show_rate": 0.08},
{"day": "saturday", "no_show_rate": 0.09},
{"day": "sunday", "no_show_rate": 0.05}
],
"by_booking_source": [
{"source": "website", "no_show_rate": 0.05},
{"source": "phone", "no_show_rate": 0.04},
{"source": "third_party", "no_show_rate": 0.12}
],
"mitigation_effectiveness": {
"confirmation_calls": {
"reservations_confirmed": 320,
"no_show_rate_after": 0.02
},
"deposit_required": {
"reservations_with_deposit": 85,
"no_show_rate_after": 0.01
}
}
}
Floor Plan
Get Floor Plan Status
GET /api/v1/seating/floor-plan
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
Response
{
"location_id": "loc_123",
"areas": [
{
"id": "area_main",
"name": "Main Dining",
"tables": [
{
"id": "table_01",
"name": "Table 1",
"capacity": 4,
"type": "booth",
"status": "occupied",
"party_size": 3,
"seated_at": "2026-01-24T19:15:00Z",
"estimated_clear": "2026-01-24T20:45:00Z",
"server_id": "emp_001",
"position": {"x": 100, "y": 150}
},
{
"id": "table_02",
"name": "Table 2",
"capacity": 2,
"type": "table",
"status": "available",
"position": {"x": 200, "y": 150}
}
]
}
],
"summary": {
"total_tables": 25,
"occupied": 18,
"available": 5,
"reserved": 2,
"total_capacity": 92,
"current_covers": 65
}
}
Table Status Values
| Status | Description |
|---|---|
available | Ready to seat |
occupied | Currently in use |
reserved | Reserved for upcoming party |
cleaning | Being bussed/cleaned |
blocked | Temporarily unavailable |
Webhooks
| Event | Description |
|---|---|
seating.table_seated | Party seated at table |
seating.table_cleared | Table cleared and available |
seating.waitlist_ready | Waitlist party ready to seat |
seating.no_show_detected | Reservation marked as no-show |
seating.turn_time_exceeded | Table exceeding expected turn |
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | invalid_party_size | Party size exceeds capacity |
| 400 | table_unavailable | Table not available |
| 404 | table_not_found | Table ID not found |
| 409 | already_seated | Reservation already seated |
Related Documentation
- Reservations API - Reservation management
- Tables API - Table configuration
- Analytics API - Business analytics