Skip to main content

Driving-School Bookings

The Bookings API powers an online booking experience on your own website: customers find an instructor who services their suburb, pick a lesson or package, choose an available time, and book — with optional online payment. All data comes from your Laabam One account (service locations, instructors, availability, products).

  • Base path: https://api.laabam.one/v1/schools/{company} (also reachable at https://laabam.app/api/v1/schools/{company}).
  • {company} is your company slug.
  • For an instant embeddable UI on top of these endpoints, see the Booking Widget guide.

Authentication

These endpoints accept either key type:

KeyHeader(s)Use
Secret (lk_id_… + secret)X-Client-Id + X-Client-SecretServer-to-server (your backend). Full access.
Publishable (pk_…)X-Client-Id onlyIn-browser / widget. No secret. Origin-locked.

Create keys in Settings → API Keys. A publishable key sends no secret, so it is safe to put in page source — but it only works from the origins you allow-list on the key (the browser's Origin/Referer must match). See Authentication and Security.

# Server-to-server (secret key)
curl https://api.laabam.one/v1/schools/darshan-driving/locations \
-H "X-Client-Id: lk_id_xxx" -H "X-Client-Secret: lk_secret_xxx"

# Browser (publishable key) — Origin must be allow-listed on the key
curl https://api.laabam.one/v1/schools/darshan-driving/instructors?postcode=3029 \
-H "X-Client-Id: pk_xxx" -H "Origin: https://yourschool.com"

The booking flow

  1. Locations — list your pickup points / test centres (optional).
  2. Instructors — find instructors who service the customer's suburb/postcode.
  3. Courses — list lessons & packages with prices.
  4. Availability — get bookable time slots for an instructor on a date.
  5. Create booking — match/create the customer and create the booking; optionally start payment.
  6. Status — read the booking back (e.g. after returning from payment).

List service locations

GET /schools/{company}/locations

{
"success": true,
"locations": [
{ "id": 3, "name": "VicRoads Bundoora", "type": "test_center",
"city": "Bundoora", "state": "VIC", "postcode": "3083",
"latitude": -37.70, "longitude": 145.06, "operating_hours": null }
]
}

Find instructors

GET /schools/{company}/instructors

Filter by one of (most specific first):

QueryMatch
lat + lngInstructors whose service area centre is within its radius_km of the point (distance match).
postcodeInstructors who service that postcode.
suburbInstructors who service that suburb.
location_idInstructors mapped to that service location.
(none)All bookable instructors.
curl "https://api.laabam.one/v1/schools/darshan-driving/instructors?postcode=3029" \
-H "X-Client-Id: pk_xxx" -H "Origin: https://yourschool.com"
{
"success": true,
"instructors": [
{ "id": 189, "name": "Hafeez Mohammed Abdul", "gender": null,
"languages": ["English"], "transmission": "both",
"bio": "5+ years experience.", "photo_url": null,
"service_areas": [ { "suburb": "Tarneit", "postcode": "3029", "state": "VIC", "radius_km": 20 } ] }
]
}

transmission is auto, manual, or both.

List courses (lessons & packages)

GET /schools/{company}/courses — optional ?transmission=auto|manual and ?type=lesson|package.

{
"success": true,
"courses": [
{ "id": 6356, "name": "AUTO - 2 HOUR LESSON", "price": 120, "currency": "AUD",
"duration_minutes": 120, "transmission": "auto", "is_package": false,
"product_type": "service" }
]
}

Get availability

GET /schools/{company}/availability?instructor_id={id}&date=YYYY-MM-DD[&duration_minutes=]

Returns bookable start/end slots, honouring the instructor's weekly schedule, date overrides, existing bookings, and your booking settings (slot length, buffer, min-notice, advance window).

{ "success": true, "available": true, "reason": null,
"slots": [ { "start": "09:00", "end": "11:00" }, { "start": "11:15", "end": "13:15" } ] }

When unavailable: { "available": false, "reason": "No availability set for this day", "slots": [] }.

Create a booking

POST /schools/{company}/bookings

{
"customer": { "name": "Jane Doe", "email": "jane@example.com", "phone": "0400000000",
"postcode": "3029", "city": "Tarneit" },
"instructor_id": 189,
"product_id": 6356,
"service_location_id": 3,
"booking_date": "2026-07-01",
"start_time": "10:00",
"end_time": "12:00",
"pickup_address": "1 Example St, Tarneit",
"student_notes": "First lesson",
"booking_package_id": null,
"return_url": "https://yourschool.com/booking/success",
"cancel_url": "https://yourschool.com/booking/cancel"
}
  • end_time is optional — if omitted, it's derived from duration_minutes, the product's duration, or your default slot length.
  • booking_package_id (optional) books against a customer's pre-paid package (a session is decremented and the booking is confirmed without payment).
  • return_url + cancel_url (optional) — when supplied and payment is due, payment is initiated immediately (see below).

Response (201):

{
"success": true,
"booking": { "id": 12, "booking_number": "BK-000012", "status": "pending",
"payment_status": "unpaid", "total_amount": 120, "currency": "AUD",
"booking_date": "2026-07-01", "start_time": "10:00", "end_time": "12:00" },
"payment": { "required": true, "amount": 120, "currency": "AUD",
"gateway": "stripe", "payment_url": "https://checkout.stripe.com/...",
"status": "unpaid" }
}

Pricing is always taken from your catalogue server-side (the client can't set the price).

Pay for a booking

POST /schools/{company}/bookings/{id}/pay — start (or retry) payment for a pending booking.

{ "return_url": "https://yourschool.com/booking/success",
"cancel_url": "https://yourschool.com/booking/cancel" }

Returns payment.payment_url (Stripe/PayPal) or payment.payment_data (Razorpay client fields). Redirect the customer there. The booking is automatically confirmed and marked paid by the gateway webhook once payment completes.

Online payment needs a configured gateway

Online payment requires an active payment gateway for AUD in Settings → Payment Gateways, and the gateway's webhook pointed at https://laabam.app/api/v1/storefront/{company}/webhook/{stripe|razorpay|paypal}. If no gateway is configured, the booking is still created as pending and the response carries payment.online_payment_enabled: false — fall back to "we'll contact you to arrange payment".

Get booking status

GET /schools/{company}/bookings/{id}

{ "success": true,
"booking": { "id": 12, "booking_number": "BK-000012", "status": "confirmed",
"payment_status": "paid", "total_amount": 120, "currency": "AUD",
"instructor": { "id": 189, "name": "Hafeez Mohammed Abdul" } } }

Errors

StatusMeaning
401Missing/invalid key (or missing secret for a secret key).
403Origin not allowed (publishable key from a non-allow-listed site).
404Company or booking not found.
409The chosen slot conflicts with an existing booking.
422Validation failed, or online payment not enabled.
429Rate limit exceeded.

See the full API Reference for schemas, and the Booking Widget for a drop-in UI.