Availability
Availability is built from four resources under /api/my-venues/:venueId/…, all
operator (client role, venue-scoped). Send an Authorization: Bearer token
from the Authentication flow.
- Time periods - named windows (e.g. “Dinner”) you can reference from shifts.
- Shifts - recurring service blocks that set which days/times take bookings.
- Access rules - the bookable offers guests see; each rule can override venue defaults for party size, seating, pricing, duration and more.
- Blackouts - date ranges that close bookings.
How they layer over venue defaults
Section titled “How they layer over venue defaults”Each resource only stores what you explicitly set. Where a section is left off,
the venue-level default applies at booking time. A shift carries only its
days and service window (a named time_period_id, or a custom
time_from/time_to) - party size, duration, seating and payment all resolve
from access rules, not the shift. On an access rule every feature has an
*_enabled toggle (party_size_enabled, duration_enabled,
booking_window_enabled, …) and the paired value only takes effect when its
toggle is true - otherwise the venue default is used. Creating at least one
access rule flags the venue as bookable on discovery surfaces.
| Method | Path | Purpose | Auth |
|---|---|---|---|
| GET | /api/my-venues/:venueId/time-periods |
List time periods | operator |
| POST | /api/my-venues/:venueId/time-periods |
Create a time period | operator |
| PUT | /api/my-venues/:venueId/time-periods/:id |
Update a time period | operator |
| DELETE | /api/my-venues/:venueId/time-periods/:id |
Delete a time period | operator |
| GET | /api/my-venues/:venueId/shifts |
List shifts | operator |
| POST | /api/my-venues/:venueId/shifts |
Create a shift | operator |
| PUT | /api/my-venues/:venueId/shifts/:id |
Update a shift | operator |
| DELETE | /api/my-venues/:venueId/shifts/:id |
Delete a shift | operator |
| POST | /api/my-venues/:venueId/shifts/copy |
Copy a shift set from another venue | operator |
| GET | /api/my-venues/:venueId/access-rules |
List access rules | operator |
| POST | /api/my-venues/:venueId/access-rules |
Create an access rule | operator |
| PUT | /api/my-venues/:venueId/access-rules/:id |
Update an access rule | operator |
| DELETE | /api/my-venues/:venueId/access-rules/:id |
Delete an access rule | operator |
| POST | /api/my-venues/:venueId/access-rules/:id/image |
Upload a rule image | operator |
| GET | /api/my-venues/:venueId/blackouts |
List blackouts | operator |
| POST | /api/my-venues/:venueId/blackouts |
Create a blackout | operator |
| PUT | /api/my-venues/:venueId/blackouts/:id |
Update a blackout | operator |
| DELETE | /api/my-venues/:venueId/blackouts/:id |
Delete a blackout | operator |
Time periods
Section titled “Time periods”GET /api/my-venues/:venueId/time-periods lists them. A period takes name,
time_from and time_to.
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/time-periods" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Dinner","time_from":"18:00","time_to":"23:00"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/time-periods", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Dinner", time_from: "18:00", time_to: "23:00", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/time-periods");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "name" => "Dinner", "time_from" => "18:00", "time_to" => "23:00", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "id": "tp_9f2a" }Shifts
Section titled “Shifts”Shifts define recurring service. name and a non-empty days_of_week array are
required; everything else falls back to a default. Use time_period_id to point
at a named period, or time_from/time_to for a custom window.
Create a shift
Section titled “Create a shift”curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Friday Dinner","days_of_week":["fri","sat"],"time_type":"custom","time_from":"18:00","time_to":"23:00"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Friday Dinner", days_of_week: ["fri", "sat"], time_type: "custom", time_from: "18:00", time_to: "23:00", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/shifts");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "name" => "Friday Dinner", "days_of_week" => ["fri", "sat"], "time_type" => "custom", "time_from" => "18:00", "time_to" => "23:00", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "id": "shf_123" }A shift stores only its schedule. Other accepted fields are schedule_start and
schedule_end (a date window the shift runs within) and time_period_id (pin
to a named time period instead of time_from/time_to). Party size, duration,
seating and payment are not shift settings - they live on access rules, and
any such field sent here is ignored.
A shift that overlaps another on a shared day is rejected with
400 { "error": "Overlaps with \"<name>\" on shared days." }.
Update a shift
Section titled “Update a shift”PUT /api/my-venues/:venueId/shifts/:id re-sends the same field set; name
stays required.
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Friday Dinner","days_of_week":["fri"],"time_from":"19:00","time_to":"23:30"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123", { method: "PUT", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Friday Dinner", days_of_week: ["fri"], time_from: "19:00", time_to: "23:30", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123");curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "name" => "Friday Dinner", "days_of_week" => ["fri"], "time_from" => "19:00", "time_to" => "23:30", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true }Delete a shift
Section titled “Delete a shift”curl -X DELETE "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"await fetch("https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123", { method: "DELETE", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}` },});$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/shf_123");curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "DELETE", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],]);curl_exec($ch);{ "success": true }Copy a shift set from another venue
Section titled “Copy a shift set from another venue”POST /api/my-venues/:venueId/shifts/copy re-creates every shift from a
source_venue_id in the target venue. You must be able to access both venues.
Any source shift that would overlap an existing target shift is skipped, so the
copy never creates a clash. The response reports how many were copied versus
skipped.
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/copy" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"source_venue_id":"SOURCE_VENUE_ID"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/copy", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ source_venue_id: "SOURCE_VENUE_ID" }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/shifts/copy");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode(["source_venue_id" => "SOURCE_VENUE_ID"]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "copied": 3, "skipped": [] }Access rules
Section titled “Access rules”An access rule is the bookable offer a guest picks. Only name is required; the
rule is a large object where each feature has an *_enabled toggle plus its
values. Set rule_type to "tables" for table bookings, "guestlist" for the
door list, or "privatehire" for exclusive-use enquiries. Any unrecognised
value falls back to "tables". Any feature you leave disabled falls back to the
venue default.
Create an access rule
Section titled “Create an access rule”curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"VIP Booth","rule_type":"tables","days_of_week":["fri","sat"],"time_from":"21:00","time_to":"03:00","party_size_enabled":true,"party_size_min":2,"party_size_max":12,"table_assignment_mode":"guest_pick","duration_enabled":true,"duration_minutes":180,"display_enabled":true,"display_title":"VIP Booth","display_description":"Bottle service included"}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "VIP Booth", rule_type: "tables", days_of_week: ["fri", "sat"], time_from: "21:00", time_to: "03:00", party_size_enabled: true, party_size_min: 2, party_size_max: 12, table_assignment_mode: "guest_pick", duration_enabled: true, duration_minutes: 180, display_enabled: true, display_title: "VIP Booth", display_description: "Bottle service included", }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "name" => "VIP Booth", "rule_type" => "tables", "days_of_week" => ["fri", "sat"], "time_from" => "21:00", "time_to" => "03:00", "party_size_enabled" => true, "party_size_min" => 2, "party_size_max" => 12, "table_assignment_mode" => "guest_pick", "duration_enabled" => true, "duration_minutes" => 180, "display_enabled" => true, "display_title" => "VIP Booth", "display_description" => "Bottle service included", ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "id": "acr_77" }Further optional sections (each gated by its *_enabled flag): seating_enabled
seating_area_ids/table_ids,bundles_enabled+bundle_ids,booking_window_enabled+booking_cutoff_value/booking_cutoff_unit+booking_start_value/booking_start_unit,max_covers_enabled+max_covers,venue_access_enabled/free_guest_list_enabled/paid_guest_list_enabled/queue_skip_price_enabled/surge_threshold_enabled/surge_price_enabledwith their_valuefields,pricelist_id,payment_policy_id,list_profile_id,table_profile_idandapp_opt_out.
Other rule-level fields:
table_assignment_mode- how a table is picked:"auto"(default),"guest_pick"(guest chooses any table), or"guest_pick_area"(guest chooses within areas listed inguest_pick_area_ids; an entry can also be"group:<groupId>"for a seating area group).booking_policy_type+booking_policy_custom- the booking policy shown for the rule.schedule_start/schedule_end- a date window the rule runs within. When both are set to the same date, the rule is a single-day rule and nodays_of_weekis required (the date supplies the weekday).time_type+time_period_id- pin the rule to a named time period instead oftime_from/time_to.override_schedule(0/1) - when1, the rule replaces every other rule of the samerule_typeon the days it is active.show_as_experience(true/false) - list a"tables"rule as an experience (ignored for other rule types).custom_colour- a#RGB/#RRGGBBhex used as a colour marker in the operator grid; any other value is stored as no colour.
A rule’s time window must fall inside an existing shift’s hours on every day it
runs, or the save is rejected with 400. Rules of type "privatehire", and any
rule with override_schedule set to 1, are exempt from this check.
The rule’s reservation_tags column is not settable through this API - it is
derived from the rule’s linked profile, so sending it here has no effect.
Update an access rule
Section titled “Update an access rule”PUT /api/my-venues/:venueId/access-rules/:id accepts the same body.
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"VIP Booth","rule_type":"tables","party_size_enabled":true,"party_size_min":4,"party_size_max":12}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77", { method: "PUT", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "VIP Booth", rule_type: "tables", party_size_enabled: true, party_size_min: 4, party_size_max: 12, }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77");curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "name" => "VIP Booth", "rule_type" => "tables", "party_size_enabled" => true, "party_size_min" => 4, "party_size_max" => 12, ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true }Delete an access rule
Section titled “Delete an access rule”curl -X DELETE "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN"await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77", { method: "DELETE", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}` }, },);$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77");curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "DELETE", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],]);curl_exec($ch);{ "success": true }Upload a rule image
Section titled “Upload a rule image”POST /api/my-venues/:venueId/access-rules/:id/image sets the rule’s display
image. Send the image as a base64 data URL in a data field (max 2 MB); the
response returns the stored URL and writes it to the rule’s display_image_url.
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77/image" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"data":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAA..."}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77/image", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ data: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAA...", }), },);const { url } = await res.json();$dataUrl = "data:image/jpeg;base64," . base64_encode(file_get_contents("booth.jpg"));$ch = curl_init( "https://thesidedoor.co/api/my-venues/VENUE_ID/access-rules/acr_77/image");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode(["data" => $dataUrl]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "url": "/assets/access-rules/VENUE_ID/acr_77.jpg" }Blackouts
Section titled “Blackouts”A blackout closes bookings over a date range. date_from and date_to are
required; description and the affects_guestlist/affects_events/
affects_reservations toggles are optional.
Create a blackout
Section titled “Create a blackout”curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/blackouts" \ -H "Authorization: Bearer $SIDEDOOR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"date_from":"2026-12-24","date_to":"2026-12-26","description":"Holiday closure","affects_guestlist":true,"affects_events":true,"affects_reservations":true}'const res = await fetch( "https://thesidedoor.co/api/my-venues/VENUE_ID/blackouts", { method: "POST", headers: { Authorization: `Bearer ${process.env.SIDEDOOR_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ date_from: "2026-12-24", date_to: "2026-12-26", description: "Holiday closure", affects_guestlist: true, affects_events: true, affects_reservations: true, }), },);const data = await res.json();$ch = curl_init("https://thesidedoor.co/api/my-venues/VENUE_ID/blackouts");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$token}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "date_from" => "2026-12-24", "date_to" => "2026-12-26", "description" => "Holiday closure", "affects_guestlist" => true, "affects_events" => true, "affects_reservations" => true, ]),]);$data = json_decode(curl_exec($ch), true);{ "success": true, "id": "blk_5a" }Update with PUT /api/my-venues/:venueId/blackouts/:id (same fields; 404 if
the id does not match) and remove with DELETE /api/my-venues/:venueId/blackouts/:id, each returning { "success": true }.