Website schedule embed¶
Use this guide when your goal is to display live class schedules, appointments, venues, or teacher information on an external website.
Who this is for¶
- Companies that want to show their timetable on their own website without using the bsport widget.
- Development teams building a custom booking or discovery experience on top of bsport schedule data.
What you can do¶
Four read endpoints provide structured access to schedule data:
| Endpoint | Description |
|---|---|
GET /api/v2/management/classes/ |
List class sessions with dates, times, and capacity |
GET /api/v2/management/appointments/ |
List booked appointments (not free time slots) |
GET /api/v2/management/venues/ |
List venue details (name, address, location) |
GET /api/v2/management/teachers/ |
List teacher profiles (name, bio, photo) |
The classes endpoint defaults to the next 30 days
GET /api/v2/management/classes/ filters on starts_after (defaults to now)
and starts_before (defaults to now + 30 days). Omitting both returns only the
next 30 days of classes. The example below passes both explicitly, which is
what you want for a schedule embed.
Recommended architecture: scheduled cache refresh¶
Fetch schedule data on your server side and serve it from your own cache. Refresh on a regular interval.
Website visitor request
-> Your backend (cached schedule data)
-> Rendered schedule page
Background job (every 15-60 min)
-> Public API: classes, appointments, venues, teachers
-> Update cache
Never call the API from client-side JavaScript
Calling the API directly from the browser exposes your API key to visitors. Always proxy requests through your backend.
import requests
import time
from datetime import datetime, timedelta, timezone
# YOUR_ENV_DOMAIN: public.staging.bsport.io or public.production.bsport.io
BASE_URL = "https://YOUR_ENV_DOMAIN"
HEADERS = {
"X-Api-Key": "YOUR_API_KEY",
"X-Client-ID": "YOUR_CLIENT_ID",
"X-Company-ID": "YOUR_COMPANY_ID",
}
def fetch_all(path: str, extra_params: dict = None) -> list:
results = []
page = 1
while True:
params = {"page_size": 100, "page": page, **(extra_params or {})}
response = requests.get(f"{BASE_URL}{path}", headers=HEADERS, params=params)
response.raise_for_status()
data = response.json()
results.extend(data["results"])
page = data["next_page"]
if page is None:
break
time.sleep(0.3) # stay within rate limit
return results
def build_schedule_cache() -> list:
today = datetime.now(timezone.utc)
next_week = today + timedelta(days=7)
venues = {v["id"]: v for v in fetch_all("/api/v2/management/venues/")}
teachers = {t["id"]: t for t in fetch_all("/api/v2/management/teachers/")}
classes = fetch_all(
"/api/v2/management/classes/",
extra_params={
"starts_after": today.isoformat(),
"starts_before": next_week.isoformat(),
},
)
for cls in classes:
cls["venue"] = venues.get(cls.get("venue_id"))
cls["teacher"] = teachers.get(cls.get("teacher_id"))
return classes
schedule = build_schedule_cache()
# Store the schedule in your backend cache.
Webhook alternative: event-driven cache invalidation¶
Use V2 class webhooks to invalidate and refresh your cache as soon as a class changes, instead of waiting for the next scheduled refresh.
Public API event (class.created or class.updated)
-> your webhook endpoint
-> trigger build_schedule_cache()
-> update cache
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/webhook/bsport", methods=["POST"])
def handle_bsport_event():
raw_body = request.get_data()
verify_bsport_signature(raw_body, request.headers["Bsport-Signature"])
payload = request.get_json()
event_type = payload["event_type"]
if event_type in ("class.created", "class.updated"):
schedule = build_schedule_cache()
store_in_cache(schedule)
return jsonify({"status": "accepted"}), 200
verify_bsport_signature is defined in
Delivery, signatures and retries.
The event data object is the current Class resource. See the
event catalogue for the complete
payload schema.
API key scope¶
For a single-company website, use a Company API key scoped to that company. Do not use a Franchisor API key for a single-company embed as it grants broader access than needed.
See Headers and tenant context.
Limitations¶
Automate bookings for your company
The booking endpoints are intended for your company team's workflows and third-party automation tools, not for client-facing booking interfaces. You cannot accept client bookings directly through the Public API.
Client booking: If your website needs to accept client bookings, you have two options: 1. Embed the bsport widget - use the turnkey bsport booking widget 2. Contact bsport - discuss custom booking solutions with your account manager
Schedule display: You can freely display class schedules, capacity, and availability using the read-only endpoints documented above.
Capacity and waitlist data:
Classes expose current_bookings, max_capacity, max_waitlist_size and
current_waitlist_size. Appointments represent existing private bookings and do not
expose these capacity or waitlist counters. Appointment slots describe duration and
credit cost, not free time windows.
Check the API reference for each endpoint to confirm which fields are available.