Resources API
The Resources API allows clients to browse bookable resources and check their availability.
List Resources
Retrieve a list of all active, bookable resources.
Request:
GET /api/v1/resources/
Query Parameters:
| Name | Type | Description |
|---|---|---|
| venue | integer | Filter by venue ID |
| venue_slug | string | Filter by venue slug |
| activity | integer | Filter by activity type ID |
| is_active | boolean | Filter by active status |
| is_bookable | boolean | Filter by bookable status |
Response:
[
{
"id": 1,
"name": "Court 1",
"description": "Indoor tennis court with clay surface",
"venue": 1,
"venue_name": "Sports Center Munich",
"venue_slug": "sports-center-munich",
"capacity": 4,
"base_price": "25.00",
"currency": "EUR",
"price_unit": "hour",
"booking_interval_minutes": 30,
"min_booking_duration_minutes": 60,
"max_booking_duration_minutes": 180,
"prevent_unbookable_gaps": true,
"is_active": true,
"is_bookable": true,
"attributes": {}
}
]
Get Resource Details
Retrieve detailed information about a specific resource including venue details and availability schedules.
Request:
GET /api/v1/resources/{id}/
Response:
{
"id": 1,
"name": "Court 1",
"description": "Indoor tennis court with clay surface",
"venue": {
"id": 1,
"name": "Sports Center Munich",
"slug": "sports-center-munich",
"address": "Sportstrasse 1, 80000 Munich"
},
"activity_types": ["Tennis", "Badminton"],
"capacity": 4,
"base_price": "25.00",
"currency": "EUR",
"price_unit": "hour",
"dynamic_pricing_enabled": false,
"min_price": "20.00",
"max_price": "40.00",
"current_demand_level": 0.5,
"attributes": {},
"booking_interval_minutes": 30,
"min_booking_duration_minutes": 60,
"max_booking_duration_minutes": 180,
"prevent_unbookable_gaps": true,
"min_advance_booking_minutes": 60,
"max_advance_booking_days": 30,
"is_active": true,
"is_bookable": true,
"availability_schedules": [
{
"id": 1,
"schedule_type": "recurring",
"day_of_week": 1,
"day_of_week_display": "Monday",
"specific_date": null,
"start_date": null,
"end_date": null,
"priority": 0,
"is_active": true,
"time_slots": [
{
"id": 1,
"start_time": "08:00:00",
"end_time": "22:00:00",
"price_per_unit": "25.00",
"pricing_unit": "hour",
"slot_duration_minutes": 60,
"capacity_override": null,
"label": "",
"is_bookable": true
}
]
}
],
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-01T10:00:00Z"
}
Get Resource Availability
Retrieve availability windows, existing bookings, and booking constraints for a resource. The frontend uses this data to calculate valid booking start times and durations.
Request:
GET /api/v1/resources/{id}/availability/
Query Parameters (required):
| Name | Type | Description |
|---|---|---|
| start_date | string | Start date in YYYY-MM-DD format |
| end_date | string | End date in YYYY-MM-DD format (max 31 days from start) |
Example:
curl -X GET "http://127.0.0.1:8000/api/v1/resources/1/availability/?start_date=2025-01-15&end_date=2025-01-16"
Response:
{
"resource_id": 1,
"resource_name": "Court 1",
"start_date": "2025-01-15",
"end_date": "2025-01-16",
"timezone": "Europe/Berlin",
"booking_interval_minutes": 30,
"min_duration_minutes": 60,
"max_duration_minutes": 180,
"prevent_unbookable_gaps": true,
"min_advance_booking_minutes": 60,
"max_advance_booking_days": 30,
"windows": [
{
"date": "2025-01-15",
"start_time": "08:00:00",
"end_time": "22:00:00",
"price_per_hour": "25.00",
"currency": "EUR",
"label": "",
"booking_interval_minutes": 30,
"min_duration_minutes": 60,
"max_duration_minutes": 180,
"prevent_unbookable_gaps": true
}
],
"booked_slots": [
{
"start_datetime": "2025-01-15T10:00:00+01:00",
"end_datetime": "2025-01-15T11:30:00+01:00",
"booking_id": "550e8400-e29b-41d4-a716-446655440000"
}
],
"unavailable_periods": []
}
Response Fields
Constraints (resource-level):
| Field | Type | Description |
|---|---|---|
| booking_interval_minutes | integer | Booking start times must align to this interval (e.g., 30 = :00, :30) |
| min_duration_minutes | integer | Minimum booking duration |
| max_duration_minutes | integer | Maximum booking duration (null = no limit) |
| prevent_unbookable_gaps | boolean | If true, bookings that would leave unbookable gaps are rejected |
| min_advance_booking_minutes | integer | Minimum minutes in advance to book |
| max_advance_booking_days | integer | Maximum days in advance to book |
Windows - Time periods when the resource is available:
| Field | Type | Description |
|---|---|---|
| date | string | The date (YYYY-MM-DD) |
| start_time | string | Window start time (HH:MM:SS) |
| end_time | string | Window end time (HH:MM:SS) |
| price_per_hour | string | Price per hour for this window |
| currency | string | Currency code (e.g., "EUR") |
| label | string | Optional label (e.g., "Peak Hours", "Happy Hour") |
Booked Slots - Existing bookings that block availability:
| Field | Type | Description |
|---|---|---|
| start_datetime | string | Booking start (ISO 8601) |
| end_datetime | string | Booking end (ISO 8601) |
| booking_id | string | Reference to the booking |
Unavailable Periods - Maintenance, holidays, etc.:
| Field | Type | Description |
|---|---|---|
| start_datetime | string | Period start (ISO 8601) |
| end_datetime | string | Period end (ISO 8601) |
| reason | string | Reason code (maintenance, holiday, etc.) |
Frontend Calculation Logic
The frontend should calculate valid booking times as follows:
- Generate valid start times within each window:
- Start at
window.start_time - Increment by
booking_interval_minutes(e.g., 08:00, 08:30, 09:00...) -
Stop when
start_time + min_duration_minutes > window.end_time -
For each start time, calculate valid end times:
- Minimum:
start_time + min_duration_minutes - Maximum:
start_time + max_duration_minutes(orwindow.end_timeif no max) -
End times should also align to
booking_interval_minutes -
Remove blocked times:
- Remove any slot that overlaps with
booked_slots -
Remove any slot that overlaps with
unavailable_periods -
If
prevent_unbookable_gapsis true: - Check that the booking doesn't leave a gap smaller than
min_duration_minutesbetween:- Start of window and booking start
- Booking end and next booking/end of window
- Previous booking end and booking start
Gap Prevention Example
Given: - Window: 08:00 - 12:00 - min_duration_minutes: 60 - Existing booking: 10:00 - 11:30
If a user tries to book 08:00 - 09:30: - Gap between 09:30 and 10:00 = 30 minutes - 30 < 60 (min_duration) = INVALID (would leave unbookable gap)
If a user tries to book 08:00 - 10:00: - No gap (ends exactly where next booking starts) = VALID
Error Responses:
400 Bad Request- Missing or invalid date parameters404 Not Found- Resource not found or not available