The Lessonluma API
Everything the coach app, the booking pages and the AI assistant do is a call to this API, so anything you can click you can automate. JSON over HTTPS, OpenAPI 3.1, signed webhooks for every event.
Authentication
Create a key in the coach app under API & webhooks. Send it as a bearer token. A key has full access to its own coach account only; keep it on your server.
curl https://new.lessonluma.com/api/v1/lessons?days=7 \ -H "Authorization: Bearer ll_live_xxxxxxxxxx_..."
Base URL: https://new.lessonluma.com/api/v1
Conventions
- Money is integer cents in CAD:
"priceCents": 7000is CA$70.00. - Times are ISO 8601 in UTC; each coach account has a
timezone. - Lists return
{ data, hasMore, nextCursor }; passlimit(max 500) andcursor. - Errors return
{ "error": { "code", "message" } }with a 4xx/5xx status. - Sign-up, booking and login endpoints are rate-limited per IP.
Webhooks
Add an endpoint (dashboard or POST /webhooks) and choose events, or * for all. Each delivery is a JSON POST with headers Lessonluma-Event, Lessonluma-Delivery and Lessonluma-Signature: t=<unix>,v1=<hex>, where v1 is an HMAC-SHA256 of <t>.<raw body> with the endpoint secret. Failed deliveries retry after 1, 5, 30, 120 and 720 minutes. Return any 2xx to acknowledge.
import crypto from "node:crypto";
// rawBody: the exact request body string; header: req.headers["lessonluma-signature"]
export function verifyLessonluma(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const a = Buffer.from(expected), b = Buffer.from(parts.v1 || "");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);
}Payload: { "id", "type", "created", "business_id", "data" }. Every coach account also has a built-in test endpoint that records what it receives, so you can see real payloads before wiring up Zapier or your own code.
Events: family.created family.updated person.created person.updated lesson.created lesson.updated lesson.moved lesson.cancelled lesson.rained_out booking.created booking.waitlisted booking.promoted booking.cancelled booking.skipped booking.attended booking.no_show recurring.created recurring.ended pack.purchased credits.added credits.low payment.created payment.succeeded payment.failed payment.refunded etransfer.matched etransfer.unmatched waiver.signed note.sent review.requested review.submitted lesson_type.created lesson_type.updated pack.created pack.updated business.created business.updated business.setup_applied business.plan_changed site.published site.unpublished
Endpoints
Auth
| post | /signup | Create a coach account (Solo free for 30 days, no card) and its booking page | public |
| post | /auth/login | Coach login (sets a session cookie) | public |
| post | /auth/reset-request | Email a coach password-reset link | public |
| post | /auth/reset | Set a new coach password from a reset link | public |
| post | /auth/logout | Log out (coach) | public |
Coach page
| get | /public/{slug} | A coach's public page: lessons, prices, packs, clinics, places, badges, reviews, policies | public |
| get | /public/{slug}/slots | Open private/semi times for a lesson type, day by day | public |
| get | /public/{slug}/lessons | Open clinics and camps with spots left (camps listed once, by their first day) | public |
| post | /public/{slug}/book | Book as a family: a private/semi time (lessonTypeId + startsAt) or a clinic/camp (lessonId), for yourself or a child | public |
| get | /public/{slug}/pay/{ref} | How to pay one lesson or pack (e-transfer address + code, or card) | public |
| post | /public/{slug}/pay/{ref} | Pay by card (test rail until the coach connects Stripe; then use checkoutUrl) | public |
| get | /public/rebook/{token} | After a rainout: the next open times for this lesson | public |
| post | /public/rebook/{token} | Rebook in one tap with the rainout credit | public |
| get | /public/{slug}/review/{token} | A review request | public |
| post | /public/{slug}/review/{token} | Leave a review (1-5 stars and a few words) | public |
Family
| get | /public/{slug}/me | Your family: people, balance, upcoming lessons, unpaid, waivers, notes | family |
| post | /public/{slug}/me/people | Add a child or the second parent/guardian | family |
| post | /public/{slug}/me/bookings/{id}/cancel | Cancel a booking (free inside the coach's window; later the lesson counts) | family |
| post | /public/{slug}/me/bookings/{id}/skip | Skip one week of a weekly lesson | family |
| post | /public/{slug}/me/packs | Buy a pack (credits land now; card, e-transfer or cash) | family |
| post | /public/{slug}/me/waiver | Sign this season's waiver for a student (guardian signs for a child) | family |
| post | /public/{slug}/me/recurring | Make a lesson weekly (same day and time) until a date | family |
| post | /public/{slug}/login | Family login | public |
| post | /public/{slug}/logout | Family logout | public |
| post | /public/{slug}/magic-link | Email a one-time sign-in link | public |
| post | /public/{slug}/claim | Sign in from an emailed link (optionally set a password) | public |
Account
| get | /business | This coach account, its page and settings | API key |
| patch | /business | Update the page (name, headline, about, city, sports, e-transfer address, tax number, settings) | API key |
| get | /business/plan | Plan, trial, active students vs the Free limit, pause days left | API key |
| get | /locations | Places you teach | API key |
| post | /locations | Add a place (outdoor places get the evening forecast heads-up) | API key |
| patch | /locations/{id} | Edit a place | API key |
| get | /badges | Dated credentials you show on your page (certification, police check, insurance, first aid) | API key |
| post | /badges | Add a dated badge (shown as your claim with its date, never as 'verified') | API key |
| delete | /badges/{id} | Remove a badge | API key |
| patch | /staff/{id} | A coach's public name and short bio | API key |
Setup
| post | /setup/describe | Describe your coaching in a sentence or two; the page, lessons, packs, clinics and hours are set up from it | API key |
Lessons
| get | /lesson-types | What you sell: privates, semi-privates, clinics, camps | API key |
| post | /lesson-types | Add a lesson type | API key |
| patch | /lesson-types/{id} | Change a lesson type (price, length, capacity, runs-with, active) | API key |
| get | /packs | Lesson packs on sale | API key |
| post | /packs | Add a pack (3/5/10 lessons, optional expiry) | API key |
| patch | /packs/{id} | Change or retire a pack | API key |
| get | /availability | Weekly windows when privates can be booked | API key |
| put | /availability | Replace your weekly windows (windows[], or text lines like 'Mon-Fri 16:00-20:00') | API key |
| get | /slots | Open private/semi start times on a date | API key |
| get | /lessons | Your calendar: lessons with rosters (default today + 14 days) | API key |
| post | /lessons | Schedule a clinic, or a camp across several days (one checkout books every day) | API key |
| patch | /lessons/{id} | Move a lesson (families are told) or change its notes/capacity | API key |
| post | /lessons/{id}/cancel | Cancel a lesson (credits back, families told) | API key |
| get | /today | Today and tomorrow at a glance (lessons, unpaid, forecast) | API key |
Rain
| post | /lessons/{id}/rain | The rain button for one lesson: credits back, everyone texted with the next open times | API key |
| post | /rain | The rain button for a whole day (outdoor places, or all places) | API key |
| post | /forecast/check | Run tomorrow's forecast check now (normally automatic in the evening) | API key |
Families
| get | /families | Families (search by name, email, phone or reference code) | API key |
| post | /families | Add a family: a guardian (or adult learner) and students | API key |
| get | /families/{id} | One family: people, balance, bookings, payments, waivers, notes | API key |
| post | /families/{id}/people | Add a child, an adult learner or the second guardian | API key |
| patch | /people/{id} | Edit a person | API key |
| post | /families/{id}/credits | Give credits (make-up, goodwill) | API key |
| post | /families/{id}/packs | Sell a pack to a family (e-transfer/cash tracked, card via the pay link) | API key |
| post | /notes | Send a two-line progress note (and a clip link) to the family | API key |
| post | /waivers/sign | Record a waiver signed on the coach's phone at the court | API key |
| get | /waivers/{id}/pdf | A signed waiver as PDF | API key |
| get | /messages | Outbox: every email/text sent for this account (with CASL basis and status) | API key |
Bookings
| get | /bookings | Bookings (filter by family, student or lesson) | API key |
| post | /bookings | Book a student: a private/semi at a time (lessonTypeId + startsAt) or a clinic/camp seat (lessonId) | API key |
| post | /bookings/{id}/cancel | Cancel a booking (coach cancels never count as late) | API key |
| post | /bookings/{id}/skip | Skip one week of a weekly series (the series keeps going) | API key |
| post | /bookings/{id}/attendance | Mark attended or no-show | API key |
| post | /recurring | Weekly series: 'Tuesdays 4:30 with Maya until June' (each week booked 3 weeks ahead) | API key |
| get | /recurring | Weekly series | API key |
| delete | /recurring/{id} | End a weekly series (future weeks cancelled, credits back) | API key |
Payments
| get | /payments | Payments (pending = unpaid e-transfer/cash/card) | API key |
| post | /payments/{id}/paid | One tap: mark paid (e-transfer arrived, cash in hand) | API key |
| post | /payments/{id}/void | Cancel an unpaid charge | API key |
| get | /payments/inbox | Deposit emails forwarded to your private address, and what they matched | API key |
| post | /payments/inbox | Paste a bank deposit email (same matching as forwarding it) | API key |
| post | /payments/stripe/connect | Connect your own Stripe account (cards, Apple Pay, Google Pay) | API key |
| post | /payments/stripe/refresh | Re-check the Stripe connection | API key |
AI
| post | /operator | Ask the AI operator in plain words ('move Thursday's 4:30 to Friday and tell Maya's mum') | API key |
Plan
| post | /billing/checkout | Start an upgrade checkout (Solo CA$19/mo or CA$190/yr, Academy CA$49, Academy 15 CA$99) | API key |
| post | /billing/checkout/complete | Finish the simulated (test) checkout; only while Lessonluma's Stripe keys are not set | API key |
| post | /billing/pause | Pause for the off-season (CA$0, up to 6 months a year; a new booking wakes the plan) | API key |
| post | /billing/resume | End the pause now | API key |
| post | /billing/cancel | Cancel the paid plan (back to Free; nothing is deleted) | API key |
Internal
| post | /smoke/tick | Smoke tests only: run one cron job now | public |
| post | /smoke/forecast | Smoke tests only: run tomorrow's forecast check with a supplied forecast | API key |
Developers
| get | /api-keys | API keys (the secret is shown once, at creation) | API key |
| post | /api-keys | Create an API key (full access to this business; keep it secret) | API key |
| delete | /api-keys/{id} | Revoke an API key | API key |
| get | /webhooks | Webhook endpoints | API key |
| post | /webhooks | Subscribe a URL to events (signed with Lessonluma-Signature: t=,v1=HMAC-SHA256) | API key |
| patch | /webhooks/{id} | Pause, resume or change events | API key |
| delete | /webhooks/{id} | Delete a webhook endpoint | API key |
| post | /webhooks/{id}/test | Send a webhook.test event now | API key |
| get | /webhooks/{id}/deliveries | Recent deliveries with response codes | API key |
| get | /webhook-sink | What the built-in test endpoint received (point a webhook at testEndpoint to try it) | API key |
Website
| post | /sites | Publish the public website: a zip, files as JSON, or {url} to snapshot. Live at https://<slug>.lessonluma.com/ unless publish=false. | API key |
| get | /sites | Website versions (newest first) and which one is live | API key |
| post | /sites/{id}/publish | Make a version live (also the one-click rollback) | API key |
| delete | /sites/live | Take the custom site down (the default coach page returns) | API key |
| post | /sites/handoff-tokens | Start a Build-with-AI session: a 24-hour token that can only publish this website, and the one-line prompt for each AI | API key |
| get | /sites/handoff-tokens | Build-with-AI tokens (the secret is only shown at creation) | API key |
| delete | /sites/handoff-tokens/{id} | Revoke a Build-with-AI token | API key |
| post | /sites/build-clicks | Record a Build-with-AI click and what happened (opened=app|web|pending); feeds the 'what worked' table and AdJump site_build_started | API key |
| get | /sites/build-clicks/stats | Which launch route worked, per AI and platform | API key |
| get | /sites/publishable-key | The publishable key used in the AI kit (public by design: reads only) | API key |
| get | /sites/{id} | One version with its file list | API key |
Website data
| get | /public/{slug}/lesson-types | Lessons with exact prices and a booking link each | API key |
| get | /public/{slug}/packs | Lesson packs with prices, per-lesson price, validity and a buy link | API key |
| get | /public/{slug}/coaches | Coaches shown publicly (name, role, bio) and their dated credentials | API key |
| get | /public/{slug}/reviews | Published reviews and the average rating | API key |