# OpenCourt Help Center
# For facility operators
Everything for the people who run the club, organized the way the admin panel is. Start with the
collection that matches what you are setting up, or search for the screen you are on.
* [Community](/help/facility-operators/community/community-groups-and-chats) — Groups and chats that keep players connected.
* [Court Bookings](/help/facility-operators/court-bookings) — The schedule itself, reservations, blocking off time, dependent spaces, resources.
* [Events & Programs](/help/facility-operators/events-and-programs) — One-off and recurring events, leagues, divisions, tags, waitlists, roster communication.
* [Pricing & Discounts](/help/facility-operators/pricing-and-discounts) — Pricing models, upsells, promo codes, refunds.
* [Skill Rating](/help/facility-operators/skill-ratings/skill-rating-create-balanced-and-competitive-games) — Ratings, DUPR and WPR, and events gated by rating.
* [Memberships and Rule Sets](/help/facility-operators/memberships-and-rule-sets/memberships-and-rule-sets-overview) — Membership plans, pricing, rule sets, family and group memberships.
* [Customers & Families](/help/facility-operators/customers-and-families/adding-a-new-customer) — Adding customers, selling memberships, families, freezes, upgrades, club credit.
* [Coach Booking](/help/facility-operators/coaches/coach-booking-overview) — Coach profiles, lessons, court restrictions, the coach schedule.
* [Booking & Guest Passes](/help/facility-operators/booking-and-guest-passes/what-are-booking-passes) — Pass templates, allocation rules, guest passes, redemption.
* [Waivers](/help/facility-operators/waivers/signing-a-waiver-at-the-front-desk) — Signing online or at the front desk, checking who has signed.
* [POS & Products](/help/facility-operators/point-of-sale/purchasing-pos-terminal) — Products, categories, and the POS terminal.
* [Ad and Conversion Tracking](/help/facility-operators/ad-and-conversion-tracking) — Meta, Google Analytics 4, and Google Ads conversion tracking.
* [Access Controls & Smart Locks](/help/facility-operators/access-controls) — Smart locks, door codes, in-app unlock, and troubleshooting.
* [BayControl](/help/facility-operators/bay-control) — Locking a golf simulator bay when nobody has booked it, and opening it for the customer who did.
* [Check-In & QR Scanner](/help/facility-operators/check-in) — The front-desk QR scanner and self check-in.
* [Website Integrations](/help/facility-operators/website-and-integrations/embedding-opencourt-into-your-website) — Embedding OpenCourt in your website and the lobby TV schedule.
* [Emails & Notifications](/help/facility-operators/emails-and-notifications) — Your sender name, From address, reply-to, and sending from your own domain.
* [Payment Processing & Payouts](/help/facility-operators/payments-and-payouts/opencourt-stripe-integration) — Stripe, settlement, payouts, and "incomplete" payments.
* [Reports](/help/facility-operators/reports/understanding-the-revenue-report) — Revenue and itemized reports, bookkeeping.
* [Branded App](/help/facility-operators/branded-app/overview-how-your-branded-app-is-published) — Your own white-label app on the App Store and Google Play.
Still stuck? Email [support@getopencourt.com](mailto:support@getopencourt.com) and include your club's name.
# For players
Guides for customers of a club that runs on OpenCourt. If your question is about a club's own
rules or prices, the club is the right place to ask; this section covers how the app works.
* **Getting Started** — Your account and the app. *(coming soon)*
* **Booking a Court** — Booking and managing your court time. *(coming soon)*
* **Events & Programs** — Joining events and programs. *(coming soon)*
* **Your Membership** — Your membership and what it includes. *(coming soon)*
* [Your Family](/help/players/customers-and-families) — Adding family members to your membership.
* **Passes & Guests** — Your passes and bringing guests. *(coming soon)*
* **Booking a Coach** — Booking a lesson. *(coming soon)*
* **Waivers** — Signing your club's waiver. *(coming soon)*
* [Access Controls](/help/players/access-controls/unlock-a-door-from-the-app) — Getting through the door with a code or the app.
* [Simulator Bays](/help/players/simulator-bays) — Unlocking a golf simulator bay you booked.
* [Checking In](/help/players/check-in) — Your check-in QR code and self check-in.
* **Your Skill Rating** — Your rating and what it does. *(coming soon)*
* **Community** — Groups and chats. *(coming soon)*
Still stuck? Contact your club, or email [support@getopencourt.com](mailto:support@getopencourt.com).
# Ad and conversion tracking in OpenCourt (overview)
Ad and conversion tracking reports your real **bookings, memberships, and store sales** back to your advertising
platforms, so the money you spend on ads optimizes toward customers who actually pay — not just clicks. It works
with **Meta** (Facebook and Instagram ads), **Google Analytics 4**, and **Google Ads**.
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
Why it's worth setting up [#why-its-worth-setting-up]
* **Optimize ads toward revenue.** Meta and Google can only send you good customers if they know which ad clicks
turned into real purchases. This feature tells them.
* **It doesn't get erased by ad blockers or iPhone privacy settings.** OpenCourt reports your sales **from its own
servers** (Meta's Conversions API), not only from a browser tag — so the data keeps flowing where browser-only
pixels go dark. See [What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
* **See which "type" of sale each ad drove** — a new membership vs a court booking vs a store order — so you can
optimize and report on each separately. See [Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data).
Two ways to set it up [#two-ways-to-set-it-up]
**Do it yourself.** Follow the setup guide for each platform you use:
* [Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking) *(\~15 min)*
* [Set up Google Analytics 4](/help/facility-operators/ad-and-conversion-tracking/set-up-ga4-conversion-tracking) *(\~5 min)*
* [Set up Google Ads](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking) *(\~15 min)*
**Hand it to your marketing agency.** If an agency runs your ads, you can forward this collection to them — they'll
recognize every step. Two things to know:
* Your agency needs access to your club's **Meta Business account** and/or **Google account** (not to OpenCourt).
* One person still needs OpenCourt **admin** access to paste the IDs/tokens into **Settings → Ad and Conversion
Tracking** and accept the data-sharing disclosure — that part takes two minutes and can't be done from outside
OpenCourt.
Is my customers' data safe? [#is-my-customers-data-safe]
Short version: OpenCourt only sends what ad platforms need to match a sale to an ad — **never any card or payment
details** — and it **hashes** identifying fields like email and phone before they leave. You remain responsible
for your own privacy disclosures (privacy policy, cookie/consent banner). The full, plain-English breakdown is in
[What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
The rest of this section [#the-rest-of-this-section]
| Guide | What it covers |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking) | Create your Meta dataset, get the Dataset ID + Conversions API token, connect it in OpenCourt. |
| [Set up Google Analytics 4](/help/facility-operators/ad-and-conversion-tracking/set-up-ga4-conversion-tracking) | Add your GA4 Measurement ID to track page views and purchases in Analytics. |
| [Set up Google Ads](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking) | Connect Google Ads and map each order type to a conversion action. |
| [Send a test event](/help/facility-operators/ad-and-conversion-tracking/send-a-test-event) | Prove the connection works before real money depends on it. |
| [What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked) | The events, the data, hashing, and your privacy responsibilities. |
| [Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data) | How your sales appear in Meta, and how to split them by type. |
| [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot) | Your in-OpenCourt health dashboard and fixes for common problems. |
{/*
Maintainers: overview for the Ad and Conversion Tracking collection (PR #2935, az/meta-pixel). Feature is
flag-gated (public beta) — the beta note above is the single enablement instruction; keep it verbatim across the
setup articles. GA4 + Google Ads are documented as released per product decision, though both are still behind the
superadmin gate at time of writing — revisit the beta note when the gate is lifted.
*/}
# Monitor and troubleshoot
Everything you need to keep conversion tracking healthy lives inside OpenCourt — no log-diving in Meta or Google
required.
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
Your dashboard in OpenCourt [#your-dashboard-in-opencourt]
Open **Admin → Settings → Ad and Conversion Tracking**. Each connected provider has a **health card** showing:
* **Sent / Failed (7d)** — how many events went out and how many failed over the last 7 days.
* **Last sent** — when the most recent event went out.
* A red **"Sending is failing"** banner when recent sends are failing — this is your one signal that something
needs attention. No banner, and Sent is climbing? You're healthy.
**Nothing tells you when sending breaks — you have to look.** There is no alert email today. The banner only
appears to someone who opens this page. If you are spending on ads, check it weekly. Two limits make an old
problem easy to miss: the health card counts the **last 7 days** only, and the events table holds the most
recent **200** events. A failure that started a few weeks ago may have already scrolled out of both.
Below that, the **Recent conversion events** table lists every event OpenCourt captured. **Click any row** to
open a detail slideout with the **exact request and response payload** and a **Copy** button.
**Agencies:** the slideout payload is the ground truth of what was sent and what the platform answered. Copy
it straight into a support ticket — it answers "what exactly did you send?" without any back-and-forth.
Status glossary [#status-glossary]
| Status | Meaning |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sent** | The event was delivered and the platform accepted it. |
| **Failed** | Delivery was attempted but the platform rejected it — see the slideout for the response. On a `Refund` row it can also mean the refund is still on its way, or could not be sent (for example, tracking was turned off or the Meta token was removed). The slideout's note says which. |
| **Not sending yet** | The event was **captured but not sent yet**. This is **normal, not an error** — it's expected until your Conversions API token is live. Once your token is saved and working, new events send for real. |
Symptom → fix [#symptom--fix]
Test events don't appear in Meta [#test-events-dont-appear-in-meta]
Meta's Test Events tab is a **live listener** — open it first, keep it open, then send, and allow up to a
minute. And the test code in OpenCourt must match the one in Meta's tab **exactly** — a wrong code still
reports "Sent" but lands the events in a bucket you can't see. Full walkthrough:
[Send a test event](/help/facility-operators/ad-and-conversion-tracking/send-a-test-event).
The red "Sending is failing" banner is up [#the-red-sending-is-failing-banner-is-up]
The banner names the fix for each provider that is failing. The most common ones:
* **Meta — your Conversions API token is invalid or expired.** Generate a new token in Meta and paste it into
OpenCourt — the steps are in [Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking).
* **Google Ads — turn on enhanced conversions.** In Google Ads, go to **Goals → Conversions → Settings**, accept
the customer data terms, and turn on enhanced conversions. Then click **Check setup** on the Google Ads card
to confirm.
* **Google Ads — reconnect.** OpenCourt lost its permission to upload: the Google account that connected lost
access to your Google Ads account, or someone removed OpenCourt's access in that Google account's settings.
Click **Reconnect Google Ads** and sign in with a Google account that has access — the steps are in
[Set up Google Ads conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking).
Sales that failed before you fixed the problem are not sent again automatically. If you want them re-sent,
email **[support@getopencourt.com](mailto:support@getopencourt.com)** — the sooner the better. Click any failed row in **Recent conversion events**
to see the fix again and the platform's full response.
A Custom Conversion stopped counting bookings [#a-custom-conversion-stopped-counting-bookings]
Court, bay and lane bookings used to report as `content_category` **`event`**. They now report as **`space`**,
and the old `court` value is gone. If you built a Custom Conversion on `content_category` equals `event`, it
still counts league, clinic, tournament and open-play registrations — but no longer counts bookings. Add a
second Custom Conversion on `content_category` equals `space` to count them again. If you want one
conversion covering both, build the rule so it matches `event` **or** `space` — not a rule that requires
both, which nothing can satisfy. The recipe is in
[Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data#recipe-break-out-sale-types-with-custom-conversions).
**Rules built on `content_name` break harder.** Bookings and player fees used to report the fee label —
"Player Fee", "Court Booking". They now report the real name ("Indoor Bocce Courts", "Women's Beginner
League"), so a rule matching `content_name` *contains* `Player Fee` stops matching entirely rather than
counting less.
Expect a step change in volume around the release date. That is the rename, not a drop in real bookings.
Google Ads: bookings stopped uploading [#google-ads-bookings-stopped-uploading]
Different symptom, worse outcome. Google Ads credits a sale to the conversion action you mapped against its
order type. If your map still has a `court` row, nothing will ever match it — move that resource name to the
`space` row in **Settings → Ad and Conversion Tracking → Google Ads**. And make sure the `default` row is
filled: an order type with no mapping, and any charge OpenCourt cannot classify, falls back to `default`.
With `default` empty those conversions are never uploaded, and no error is shown.
A sale is missing [#a-sale-is-missing]
Was it rung up by staff at the front desk (an **admin or POS sale**)? Those are **excluded by design** — ad
platforms only need the sales your ads could have driven, and a front-desk sale isn't one. See
[What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
Two events for one membership sale [#two-events-for-one-membership-sale]
Expected. A new membership fires **Purchase + Subscribe** — Meta uses one for revenue and one for subscription
optimization. See [Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data).
Value looks lower than the price [#value-looks-lower-than-the-price]
Also by design: OpenCourt reports **net cash captured**, not the list price. Discounts, credits, and partial
payments all reduce the reported value — so your ad platforms optimize toward real revenue. See
[What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
Reported revenue is higher than what you actually kept [#reported-revenue-is-higher-than-what-you-actually-kept]
**Check Meta for `Refund` events.** Meta keeps the original purchase value after a refund; OpenCourt sends a
separate `Refund` event worth the amount returned. Subtract it with a custom metric in Ads Manager. Google Ads
and GA4 are never updated for a refund, and a refund to account credit is not sent anywhere — reconcile those
against OpenCourt's own reports. See
[What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
Each refund or lost chargeback gets its own row in the events table: `Refund`, then `Refund #2`, and so on. A
row **Skipped** as *already\_reversed* means Meta already had the right total, so nothing more was sent. One
skipped as *purchase\_not\_delivered* means the original sale had not reached Meta yet; OpenCourt retries it
automatically once the sale arrives.
A free booking shows up as a Lead — or not at all [#a-free-booking-shows-up-as-a-lead--or-not-at-all]
Expected. A sale that captures **$0** — fully covered by a pass, account credit, or a 100% promo code, or a
free event — reports a `Lead` with a value of 0, never a `Purchase`, and only when it is the customer's first
order at your club. A member's or returning customer's free booking sends nothing. In Google Ads a Lead is sent
only when the **free\_booking** row is mapped. See
[Free bookings are reported as a Lead](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked#free-bookings-are-reported-as-a-lead).
A sale from the app isn't credited to an ad [#a-sale-from-the-app-isnt-credited-to-an-ad]
In-app purchases are reported server-side, so the revenue arrives — but the browser pixel does not run inside
the OpenCourt app, so those sales often land without a link to a specific ad. Send your ad traffic to the web
booking pages instead. See
[Purchases made in the OpenCourt app](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
{/* Maintainers: written for PR #2935 (az/meta-pixel). "Not sending yet" is the customer-facing label for the
pre-token internal state — always use this label, never the internal name. Health card fields (Sent/Failed 7d, Last sent,
"Sending is failing" banner) and the detail slideout mirror the in-app observability surface — keep in sync if
the UI changes. One screenshot TODO above (health card + events table). */}
# Send a test event
Send a fake purchase from OpenCourt to Meta and watch it arrive — so you know the connection works **before**
real ad money depends on it. *(About 5 minutes.)*
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
**What you'll need:** your **Dataset ID** and **Conversions API token** already saved in OpenCourt (from
[Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking)), plus access to your club's **Meta
Events Manager**.
This test console is **Meta-only**. GA4 verifies through its own **Realtime** and **DebugView** reports, and
Google Ads through each conversion action's diagnostics — no OpenCourt test console needed for those.
Step 1 — Get your test event code from Meta [#step-1--get-your-test-event-code-from-meta]
1. In **Meta Events Manager**, open your dataset and go to the **Test Events** tab.
2. Select the channel **Website** — the tab shows a `test_event_code` (something like `TEST12345`).
3. Copy it.
4. In **OpenCourt → Admin → Settings → Ad and Conversion Tracking**, paste the code into the Meta card's
**Test event code** field and click **Save**.
The test event code only touches **test events** — it never affects your live tracking, so it's safe to
leave set after you're done.
Step 2 — Send and watch [#step-2--send-and-watch]
**Meta's Test Events tab is a live listener, not a log.** Open the Test Events tab in Meta **first** and keep it open, **then** click Send test event in OpenCourt. Events can take up to a minute to appear.
The code in OpenCourt must match the code in Meta's Test Events tab **exactly.** A wrong code still reports "Sent," but the events land in a bucket you can't see.
1. **Open Meta's Test Events tab** (Events Manager → your dataset → **Test Events** → channel **Website**) and
**keep it open.**
2. **In OpenCourt**, go to the Meta card's **Send a test event** area, pick a scenario from the dropdown, and
click **Send test event**. (The **View in Meta Events Manager** link next to the button jumps you straight
to the right place in Meta.)
3. **Watch the Test Events tab** — your events should appear within about a minute, listed under your test code.
OpenCourt reports honestly after sending — something like: *"Sent 2 events to Meta with test code TEST12345.
Meta accepted them — that doesn't mean they're visible yet. Open your Meta Events Manager → Test Events tab and
check they appear under that same code."* "Accepted" only means Meta received the request — Meta counts events
as received **whether or not the code matched** — so seeing them in the Test Events tab is the actual proof.
What each scenario sends [#what-each-scenario-sends]
| Scenario | Events fired |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Membership purchase | **Purchase + Subscribe** — you'll see two events; this is correct. See [Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data). |
| Presale membership | Purchase only — a deposit is not yet a recurring membership |
| Pass package | Purchase |
| Subscription / package | Purchase + Subscribe |
| Product purchase | Purchase |
| Space booking (host) | Purchase |
| Join a booking (Open Game) | Purchase |
| Join an event | Purchase |
| League registration | Purchase |
| Free booking (Lead) | **Lead** only — value 0, never a Purchase. A real free order sends it only for a new customer. See [Free bookings are reported as a Lead](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked#free-bookings-are-reported-as-a-lead). |
| Refund (reverses a sale) | **Refund** only — worth the amount returned (here $10 of a $24 booking), not the sale. It is what OpenCourt sends Meta when a sale is refunded or a chargeback is lost. |
Nothing appeared? [#nothing-appeared]
Head to [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot) — it covers the two usual suspects (tab not
open first, code mismatch) and everything else.
{/* Maintainers: written for PR #2935 (az/meta-pixel) from the in-app Meta test console (scenario dropdown +
Send test event + View in Meta Events Manager deep link; uses the stored Test event code). Scenario→event
mapping mirrors the console config — keep in sync if scenarios change. One screenshot TODO above (Meta Test
Events tab); consider a second of OpenCourt's Send a test event area when available. */}
# Set up Google Analytics 4 conversion tracking
Connect your Google Analytics 4 property to OpenCourt so your club's page views, checkouts, and purchases show up in your GA4 reports. *About 5 minutes.*
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
Once you save your Measurement ID, OpenCourt automatically fires GA4 `page_view`, `begin_checkout`, and `purchase` events (with items) — and `generate_lead` instead of `purchase` for a new customer's free ($0) booking — from your club's pages using Google's gtag.js. Everything runs in the browser — there's no server key or API setup.
What you'll need [#what-youll-need]
* A **Google Analytics 4 property** with a web data stream
* **OpenCourt admin** access for your club
Working with a marketing agency? They can grab the Measurement ID from your GA4 property and hand it to you (or anyone with OpenCourt admin access) to paste into OpenCourt — that's the whole setup.
Steps [#steps]
1. **Copy your Measurement ID from Google Analytics.** In GA4, go to **Admin → Data Streams**, open your web stream, and copy the **Measurement ID** — it looks like `G-XXXXXXXXXX`.
2. **Paste it into OpenCourt.** Go to **Admin → Settings → Ad and Conversion Tracking**, find the **Google Analytics 4** card, paste the ID into **Measurement ID**, and save.
The first time you turn on any tracking provider, OpenCourt shows a data-sharing disclosure. Review and accept it to continue.
Verify it's working [#verify-its-working]
Open your club's page in a browser, then check **GA4 → Reports → Realtime** (or DebugView). You should see a `page_view` within a minute or two. Make a test purchase and you should see a `purchase` event too.
For a full test walkthrough, see [Send a test event](/help/facility-operators/ad-and-conversion-tracking/send-a-test-event).
Related articles [#related-articles]
* [What OpenCourt sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked) — the exact events and fields
* [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot) — if events aren't showing up
* [Set up Google Ads conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking) — report sales to Google Ads for campaign optimization
{/* Maintainers: drafted from PR #2935 product facts (GA4 card = single Measurement ID field, gtag.js browser-side, auto page_view/begin_checkout/purchase). Deliberately kept light on Google's exact UI paths (their menus move); screenshots intentionally omitted for now. Re-confirm the GA4 Admin path if a reader reports it drifted. */}
# Set up Google Ads conversion tracking
Connect your Google Ads account so OpenCourt reports your real sales — memberships, court bookings, events, store orders — back to Google Ads, letting Google optimize your campaigns toward customers who actually pay. *About 15 minutes.*
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
OpenCourt uploads every online sale to Google Ads from our servers. Google then credits the sales it can match to one of your ads — by the Google click id (gclid) when the customer arrived from an ad, and by the customer's hashed email and phone otherwise. You'll connect your account and tell OpenCourt which **conversion action** to credit for each order type.
What you'll need [#what-youll-need]
* A **Google Ads account** and its **10-digit account ID** (shown in the top corner of Google Ads)
* Permission to **create conversion actions** and **change conversion settings** in that account
* **OpenCourt admin** access for your club
This splits cleanly with a marketing agency: they create the conversion actions in Google Ads and click **Connect Google Ads** to authorize the upload; you (or they, with OpenCourt admin access) paste the resource names into OpenCourt.
Steps [#steps]
1. **In Google Ads, create the conversion actions you want to track.** Create at minimum one general conversion action, and optionally one per sale type (memberships, space bookings, events, store). Choose **Import** and track **conversions from clicks**, so the action's source shows as *Import from clicks* — not a website-tag conversion — because OpenCourt uploads them from our servers.
2. **Turn on enhanced conversions.** In Google Ads, go to **Goals → Conversions → Settings**. Accept the **customer data terms**, and turn on **enhanced conversions** (Google may show it as *enhanced conversions for leads*). You don't need to change the method dropdown next to it. Without this step, Google rejects every sale from a customer who didn't click an ad, which is most of them.
3. **Find each conversion action's resource name.** It has the form `customers//conversionActions/`, for example `customers/1234567890/conversionActions/456`. Note it down for each action you created. (If you can't locate the resource name, your marketing agency or Google Ads support can provide it.)
4. **Enter your account IDs in OpenCourt.** Go to **Admin → Settings → Ad and Conversion Tracking** and open the **Google Ads** card. Enter your **Google Ads account ID** — the 10-digit number, with no dashes. If a manager (MCC) account runs your ads, also fill in the **Agency / manager account ID**; otherwise leave it blank.
5. **Click Connect Google Ads.** Sign in with a Google account that has access to your Google Ads account — and to
the manager account, if you entered one. Google asks you to let OpenCourt **see, edit, create, import, or
delete your customer data in Google Ads**. That is Google's standard wording for the permission its Data
Manager API needs, and it is how OpenCourt uploads conversions. OpenCourt uses it only to upload your sales to
the conversion actions you map below.
6. **Map conversion actions to order types.** In **Conversion actions by order type**, paste the resource name from step 3 next to each order type you want to track — membership, membership\_renewal, membership\_presale, pass\_package, space, add\_on, event, day\_fee, coach\_lesson, store, gift\_card. Fill the **default** row as the catch-all for any type without its own mapping. Save.
The **free\_booking** row is different: it is for a new customer's free ($0) booking, which OpenCourt reports as a `Lead`
with a value of 0. Map it to a **separate** conversion action if you want to track a free-first-session
offer, or leave it empty to not send free bookings at all. It never falls back to `default`, so a $0
conversion can never land in a revenue action.
**Fill in `default`, even if you map every other row.** Any order type you leave blank falls back to
`default` — and so does any charge OpenCourt cannot classify. If `default` is empty, those conversions are
never uploaded to Google Ads, and nothing warns you.
{/* MD028: separates two consecutive alert blockquotes; a bare blank line merges them. */}
**Court and bay bookings are `space`, not `court`.** The old `court` row is retired. If you set one up
before September 2026, move its resource name to `space` — the `court` row is no longer sent and will never
be credited.
The first time you turn on any tracking provider, OpenCourt shows a data-sharing disclosure. Review and accept it to continue.
OpenCourt sends all of your online sales, including sales from customers who didn't click an ad — Google requires this. Google Ads credits only the sales it can link to an ad, so sales from other channels won't appear as conversions, and that's expected.
Verify it's working [#verify-its-working]
After you connect and after each save, OpenCourt runs a **setup check** on the Google Ads card. It asks Google to check a test conversion for each conversion action you mapped — nothing is recorded in your Google Ads account. You can run it again at any time with **Check setup**.
* **Ready** — Google will accept your conversions.
* **Not ready** — the card names the fix for each conversion action, for example "Turn on enhanced conversions and accept the customer data terms". Fix it in Google Ads, then click **Check setup** again.
Uploaded conversions can take some time to appear in Google Ads reporting. For each conversion action, Google Ads shows the upload status under **Goals → Conversions → \[your action] → Diagnostics**.
Related articles [#related-articles]
* [What OpenCourt sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked) — the exact events and fields
* [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot) — if conversions aren't showing up
* [Set up GA4 conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-ga4-conversion-tracking) — see the same activity in Google Analytics
{/* Maintainers: drafted from PR #2935 product facts (Google Ads card = account ID no-dashes + optional manager/MCC ID + OAuth Connect button + per-order-type conversion action resource names with default fallback; offline click conversions matched by gclid). Kept deliberately light on Google's exact UI paths (their menus move) and screenshots are intentionally omitted for now. The conversion-action resource-name step is the one worth verifying with a real account when convenient. Updated for PR #3292 (OC-3338): uploads moved to the Data Manager API (scope `datamanager`, no developer token); pre-2026-09-24 tokens carry only `adwords` and must reconnect. Do not mention Google's unverified-app screen — Google verified the app on 2026-09-24. Updated again 2026-09-24: added the enhanced-conversions + customer-data-terms step (Pickle Alley's uploads failed without it), 'Import from clicks', the setup check and its Ready / Not ready states; OpenCourt uploads every online sale, not only click-id sales. */}
# Set up Meta conversion tracking
Connect your club to **Meta** (Facebook and Instagram ads) so every booking, membership, and store sale reports
back to your ads. *(About 15 minutes. You do Part 1 in Meta and Part 2 in OpenCourt.)*
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
**What you'll need:** admin access to your club's **Meta Business account** (Events Manager) and OpenCourt **admin**
access.
If a marketing agency runs your Meta ads, forward them this page. They can do **Part 1** on their own — you only
need to paste the two values into OpenCourt in **Part 2**.
Part 1 — Create your dataset in Meta [#part-1--create-your-dataset-in-meta]
You'll end Part 1 with two things to copy: a **Dataset ID** and a **Conversions API access token**.
**1. Open Events Manager and click "Connect data".**
**2. Choose "Web" as the data source, then continue.**
**3. Name your dataset** (e.g. your club name) and **keep the "Conversions API" option checked**, then create it.
**4. Close the "Connect your web data" screen — don't install anything.** Meta offers to install a pixel here (add
code to your site, email a developer, or set up with a partner). You don't need any of it — OpenCourt sends the
events for you. Click the **X** in the top-right corner (or **Close**) to dismiss the screen.
**5. Open "Datasets" in the sidebar** and select the dataset you just created.
**6. Go to the dataset's "Settings" tab and copy the "Dataset ID".** It's a 15–16 digit number.
Meta renamed **Pixel ID → Dataset ID** (and **Data sources → Datasets**). They're the same thing — if a guide or
your agency says "Pixel ID," they mean this Dataset ID.
**7. In the "Conversions API" section, generate an access token.** Choose **"Set up with Dataset Quality API"** —
it's Meta's recommended option, takes the same number of clicks, and lets OpenCourt read your Meta-side match
quality later.
**8. Copy the access token when Meta shows it.**
Meta shows the token **only once**. Copy it now and paste it into OpenCourt in the next step — if you lose it,
you'll have to generate a new one.
Part 2 — Connect it in OpenCourt [#part-2--connect-it-in-opencourt]
**9. Open OpenCourt → Settings → Ad and Conversion Tracking.** In the **Meta Pixel** card:
* Paste your **Dataset ID** into the *Dataset ID* field.
* Paste your **Conversions API token** into the *Conversions API token* field.
* Leave *Test event code* empty for now — you'll use it in the next guide.
**10. Click "Save".** The first time you turn on any provider, OpenCourt shows a short **data-sharing disclosure** —
read it and confirm. (What that disclosure covers, in plain English, is in
[What OpenCourt sends — and what it never sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).)
That's it — Meta will start receiving your page views and purchases. Before you rely on it, prove the connection
with a quick test.
**Next:** [Send a test event](/help/facility-operators/ad-and-conversion-tracking/send-a-test-event) to confirm Meta is receiving your events correctly.
{/*
Maintainers: Part 1 steps + screenshots mirror _assets/marketing/README.md (captured 2026-08-08, current renamed
Meta UI). If Meta renames again, re-shoot and update. The "Set up WITH Dataset Quality API" recommendation is
documented with rationale in that README. The token-dialog screenshot is REDACTED — the live token is blacked
out; never publish a working token. setup-meta-pixel-install-options*.webp are no longer referenced — kept in
_assets for possible later use.
*/}
# Understand your conversion data in Meta
OpenCourt reports every online sale to Meta as a single `Purchase` event — the sale *type* lives in the event parameters, not the event name. This page shows you how to read those parameters, break out sale types for optimization and reporting, and set the right expectations when comparing Meta's numbers to OpenCourt's.
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
One event name, typed by parameters [#one-event-name-typed-by-parameters]
In Meta's event list you'll see `Purchase` for everything — a court booking, a store order, a membership. What kind of sale it was is carried in the parameters:
| Parameter | Example value |
| -------------------- | --------------------------------------------------------------------------------- |
| Event name | `Purchase` |
| `value` | `89.00` — net cash captured, after promos/passes/credits |
| `content_category` | `"membership"` |
| `content_name` | `"Unlimited Monthly"` |
| `event_type` | Not sent on a membership. On a league registration this row would read `"League"` |
| `content_categories` | `"membership"` — every category in the order, comma-joined |
| `is_new_customer` | `true` |
**`content_name` is the name of what was bought.** For memberships and store orders it is the plan or
product name, as above. For a program registration it is the event's own name ("Women's Beginner League").
Court and bay bookings are a special case: they have no event name of their own, so they are named after
your **space category** if you use them ("Indoor Bocce Courts"), otherwise the space itself ("Bay 9").
**A new customer's free booking fires `Lead`, not `Purchase`.** A first order that cost the customer $0 (pass, account credit,
100% promo code, free event) reports a `Lead` with a value of 0 and the same parameters as below. Build a
Custom Conversion on `Lead` to optimize a free-first-session campaign; purchase campaigns are not affected.
**A new membership fires both `Purchase` and `Subscribe` — this is expected.** Meta doesn't double-count: both events share one event ID, and Meta deduplicates per event name. `Subscribe` is your "new member acquired" signal; renewals fire `Purchase` only.
The content_category buckets [#the-content_category-buckets]
| Bucket | Meaning |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `membership` | A first-time membership purchase (also fires `Subscribe`) |
| `membership_renewal` | A recurring membership renewal payment |
| `space` | A court, bay or lane booking — someone reserving your space |
| `event` | A registration for something on your schedule: open play, a player fee, a league, clinic, tournament or program. `event_type` says which |
| `day_fee` | A day-pass / entry fee |
| `add_on` | An equipment rental added to a booking (a ball machine, a paddle) |
| `membership_presale` | A deposit taken before the club opens. Kept separate from `membership` so an acquisition campaign can exclude deposits |
| `pass_package` | A punch card or lesson bundle bought up front |
| `store` | An online store / pro-shop order |
| `coach_lesson` | A coaching lesson purchase |
| `gift_card` | A gift card purchase |
An order that mixes types is filed under the most important one: a membership sale that also books a court is
a `membership`, and a booking with a ball-machine rental attached is a `space`. Every individual line still
carries its own type inside `contents`.
Telling programs apart with event_type [#telling-programs-apart-with-event_type]
Anything attached to your schedule carries `event_type`, which is one of `OpenPlay`, `OpenGame`, `League`,
`Clinic`, `Tournament`, `Lesson` or `Other`. This is what you filter on to build a leagues-only or
clinics-only conversion.
`event_type` is **not** limited to the `event` bucket. A `space` booking carries `OpenGame` and a coach
lesson carries `Lesson`. If you want bookings only, filter on `content_category` equals `space` — filtering
on `event_type` would mix bookings in with open-play registrations.
The same list is summarized, alongside every other field OpenCourt sends, in [What OpenCourt sends to Meta and Google](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked).
Recipe: break out sale types with Custom Conversions [#recipe-break-out-sale-types-with-custom-conversions]
Meta optimizes and reports per event *name*, so to target or report on a specific sale type, create a Custom Conversion filtered on `content_category`:
1. In Meta Events Manager, open **Custom Conversions** and create a new one.
2. Choose your OpenCourt data source and select the `Purchase` event.
3. Add a rule on the `content_category` parameter — for example:
* **"New memberships"** — `content_category` equals `membership`
* **"Court and bay bookings"** — `content_category` equals `space`
* **"League signups"** — `content_category` equals `event` **and** `event_type` equals `League` (swap in
`Clinic` or `Tournament` for those). Both halves matter: `event_type` travels with anything on your
schedule, so a court booked *for* a league session carries `League` too — the `event` bucket is what
narrows it to an actual registration
* **"Anything booked on the schedule"** — `content_categories` *contains* `space` **or** `event`. A rule on
`content_category` equals both can never match, because one order carries one value
* **"Any order that included a membership"** — `content_categories` *contains* `membership`. Use this
whenever a cart can mix types; `content_category` only ever names the single most important one
* **"One specific program"** — `content_ids` contains the event's ID, which you can copy from the event's
URL in your admin panel
4. Name and save it. It's now available as an optimization goal in ad sets and as a column in reporting.
Create one Custom Conversion per revenue line you actually buy ads for. A campaign optimized on "New memberships" learns from membership buyers only — renewal payments and store orders won't muddy the signal.
Attribution expectations [#attribution-expectations]
These are server-side events, matched to ad clicks through hashed identifiers and click IDs — so expect Meta's attributed conversion counts to differ from OpenCourt's revenue reports. Some purchasers won't match to a Meta account, some sales were never ad-driven, and Meta only counts conversions inside its attribution windows. A gap between the two numbers is normal; use OpenCourt as the source of truth for revenue and Meta for *relative* performance between campaigns, ad sets, and creatives. Also remember that admin and front-desk (POS) sales are excluded by design — see [What OpenCourt sends](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked) for the full data policy.
Related articles [#related-articles]
* [Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking)
* [Send a test event](/help/facility-operators/ad-and-conversion-tracking/send-a-test-event)
* [What OpenCourt sends to Meta and Google](/help/facility-operators/ad-and-conversion-tracking/what-gets-tracked) — the full field list and privacy policy
* [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot)
{/* Maintainers: The content_category bucket table here is the canonical "how to use" copy; the privacy-angle summary lives in what-gets-tracked.md — keep both in sync when buckets change. The Purchase+Subscribe dedup callout is verbatim-standardized. The Custom Conversions recipe is kept light on Meta's exact UI path (their menus move); screenshot intentionally omitted for now. */}
# What OpenCourt sends to Meta and Google — and what it never sends
When you turn on Ad and Conversion Tracking, OpenCourt reports your online sales to the ad platforms you connect — so Meta and Google can see which ads actually bring in paying customers. This page explains exactly what gets sent, and just as importantly, what never does.
**Ad and Conversion Tracking is in public beta.** To turn it on for your club, email **[support@getopencourt.com](mailto:support@getopencourt.com)** or your OpenCourt customer success manager.
The events OpenCourt reports [#the-events-opencourt-reports]
Six things get reported, and only these:
* **A page view** — someone visited your club's booking pages (sent from their browser).
* **A checkout started** — someone reached the payment step (sent from their browser).
* **A purchase** — someone actually paid for something online. This one is sent **from OpenCourt's servers** using Meta's Conversions API, not from the customer's browser — so it still arrives even when ad blockers or iOS privacy settings block browser tracking. Your purchase data is the signal that matters most, and server-side delivery is what keeps it reliable.
* **A new membership** — when someone buys their *first* membership, a `Subscribe` event is sent **alongside** the purchase (never instead of it). Renewals, bookings, events, and store sales report a purchase only. So does a **[presale deposit](/help/facility-operators/memberships-and-rule-sets/run-a-membership-presale)**: a deposit is not a recurring membership yet, so it reports `Purchase` only — `Subscribe` fires later, if and when the presale converts.
* **A new customer's free booking** — their first online order at your club, when it cost them $0, reports a `Lead` with a value of 0, **never** a `Purchase`. See [Free bookings are reported as a Lead](#free-bookings-are-reported-as-a-lead) below.
* **A refund** — sent to Meta only, when you refund a reported sale from OpenCourt (to the card or in person),
or lose a chargeback on it. See [Refunds are reported to Meta](#refunds-are-reported-to-meta) below.
Google gets the same picture: GA4 receives `page_view`, `begin_checkout`, `purchase`, and `generate_lead` for a free booking. Google Ads receives the purchases as offline click conversions, and free bookings too if you map them (see below).
The value reported is what the customer actually paid [#the-value-reported-is-what-the-customer-actually-paid]
Each purchase carries the **net cash captured** — the amount after any promo code, pass, or account credit — never the list price. That keeps your ad optimization honest: the platforms learn to find customers based on real revenue, not inflated sticker prices.
Front-desk sales are excluded — on purpose [#front-desk-sales-are-excluded--on-purpose]
Sales your staff ring up at the front desk (admin and POS sales) are **never sent**. A walk-in who paid at the counter didn't come from an online ad, and mixing that revenue in would teach the ad platforms the wrong lessons about which ads work. Only online sales — the ones an ad could plausibly have driven — are reported.
Free bookings are reported as a Lead [#free-bookings-are-reported-as-a-lead]
If a customer covers a booking entirely with a pass, account credit, or a 100% promo code, no cash is
captured. Free events work the same way. When that free order is the customer's **first** order at your club,
OpenCourt reports it as a **`Lead`** event with a value of 0 — with the same `content_category`,
`content_name` and customer matching as a purchase.
A free order from an **existing** customer sends nothing. Most free bookings come from members and pass
holders booking against something they already bought — at the clubs where this launched, nearly all of them.
Reporting those as leads would teach the ad platforms to find people who are already your customers, and
`Lead` is the same event your own website may fire for contact forms.
A free order is **never** reported as a $0 `Purchase`. A zero-value purchase would drag down your reported
return on ad spend and teach the ad platforms to find people who never pay. Because `Lead` is a separate
event, nothing changes for a campaign that optimizes for purchases. If you run a free-first-session offer,
build a Custom Conversion on `Lead` (filter on `content_category` to narrow it, for example `space`) and
optimize that campaign for it.
* **Meta** receives the `Lead` automatically.
* **GA4** receives it as `generate_lead`.
* **Google Ads** receives it only if you map the **free\_booking** row to its own conversion action — see
[Set up Google Ads conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking). Leave that row empty and
free bookings are not sent to Google Ads. They never fall back to your `default` action.
Refunds are reported to Meta [#refunds-are-reported-to-meta]
When you refund a sale from OpenCourt — to the customer's card or in person, in full or in part — or lose a
chargeback on it, OpenCourt tells Meta, so you can measure the revenue you actually kept:
* **Meta** cannot change a purchase it has already recorded. Instead, OpenCourt sends a separate **`Refund`**
event worth the amount returned, labeled like the original sale. To see revenue after refunds in Ads
Manager, create a custom metric: purchase value minus `Refund` value. OpenCourt never subtracts more than it
reported: if a customer disputes a sale you already refunded, no second `Refund` is sent.
* **Google Ads** is **not** updated. Google's conversion upload service can only add conversions; it cannot
remove or re-value one. Reconcile Google Ads revenue against OpenCourt's own reports.
* **GA4** is not updated either. Purchases reach GA4 from the customer's browser, and a refund has no browser
session to report from.
Only sales OpenCourt reported to Meta are covered. A refund to **account credit** does not change anything:
no cash left your club, and OpenCourt reports cash. A refund issued directly in your Stripe dashboard is not sent
either — refund from OpenCourt. Refunds made before September 28, 2026 are not sent. Refunds made on or after
that date are, including any made in the days before this update reached your account.
Purchases made in the OpenCourt app [#purchases-made-in-the-opencourt-app]
The OpenCourt customer app runs the same booking site inside a native shell. Inside the app, OpenCourt
deliberately does **not** run the browser pixel — firing a tracking pixel inside an iOS app without Apple's
tracking permission prompt is a policy exposure we will not take on your behalf.
**In-app purchases are still reported.** They go out server-side through the Conversions API exactly like web
purchases, so no sale is lost. What is missing is the browser-side context: the page views, the
checkout-started events, and the click identifiers Meta uses to tie a sale back to one specific ad. So an
in-app purchase is more likely to be counted as revenue without being credited to the ad that caused it.
**Point your ad traffic at the web booking pages.** First-time visitors land there anyway, and that is where
attribution is strongest. The app is where your existing customers rebook.
What travels with each purchase [#what-travels-with-each-purchase]
A few extra fields go along with every purchase so the platforms (and you) can tell sale types apart:
| Field | What it contains |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content_category` | Which kind of sale it was — one of: `space` (a court, bay or lane booking), `event`, `day_fee`, `add_on` (equipment rental), `membership`, `membership_presale` (a deposit taken before the club opens), `pass_package` (a punch card or lesson bundle), `membership_renewal`, `store`, `coach_lesson`, `gift_card`. A charge OpenCourt cannot classify — a few legacy and manually entered charge types — is sent **without** this field rather than in a catch-all bucket |
| `content_categories` | **Every** category in the order, comma-joined in the same order as above (`membership,space`). `content_category` can only name one thing, so use this one with a *contains* rule to build "any order that included a membership" |
| `event_type` | Present whenever the purchase is attached to something on your schedule: `OpenPlay`, `OpenGame`, `League`, `Clinic`, `Tournament`, `Lesson` or `Other`. This includes `space` bookings (usually `OpenGame`) and coach lessons (`Lesson`) — it is not limited to the `event` category |
| `content_name` | The name of what was bought — the event's name, the membership plan, the product, the rented equipment, or (for a booking) your own space category or space name. When none of those can be resolved it falls back to the charge's own description, so this field is never empty |
| `content_ids` / `contents` / `num_items` | The itemized contents of the order |
| `is_new_customer` | Whether this was the person's first purchase at your club |
| `membership_status` | A coarse label only: member, non-member, or lapsed |
**Bookings and events are two different categories.** A court, bay or lane booking reports as `space`.
Registrations for open play, leagues, clinics, tournaments and other programs report as `event`, with
`event_type` naming which kind. To build a "leagues only" custom conversion, filter on
`event_type` equals `League`.
Customer identifiers are hashed before they leave OpenCourt [#customer-identifiers-are-hashed-before-they-leave-opencourt]
For an ad platform to credit a sale to an ad, it needs to recognize *which of its users* made the purchase. OpenCourt handles this with **one-way hashing (SHA-256)**: the customer's email, phone number, and a per-club customer ID are scrambled into a fingerprint before sending. Meta or Google can match that fingerprint against the hashes of their own logged-in users — but the raw email and phone number are never transmitted, and a hash can't be reversed back into them. You get accurate ad attribution without handing over your customer list in readable form.
**No card or payment details are ever sent.** OpenCourt only sends what ad platforms need to match a sale to an ad.
Your responsibilities [#your-responsibilities]
When you turn the feature on, OpenCourt shows a data-sharing disclosure that you accept — that covers OpenCourt's side of the sending. Your club remains responsible for its **own** privacy disclosures: your privacy policy should mention ad-platform data sharing, and your region may require a cookie or consent banner (for example under GDPR in Europe or CPRA in California). This isn't legal advice — if you're unsure what your region requires, check with a legal advisor.
Related articles [#related-articles]
* [Set up Meta conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-meta-conversion-tracking)
* [Set up GA4 conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-ga4-conversion-tracking)
* [Set up Google Ads conversion tracking](/help/facility-operators/ad-and-conversion-tracking/set-up-google-ads-conversion-tracking)
* [Understand your conversion data](/help/facility-operators/ad-and-conversion-tracking/understand-your-conversion-data) — how to use these fields for reporting and optimization
* [Monitor and troubleshoot](/help/facility-operators/ad-and-conversion-tracking/monitor-and-troubleshoot)
{/* Maintainers: This is the canonical trust/privacy page for the collection. If the event set (Purchase / Subscribe / Lead / Refund), enrichment fields, hashing behavior, or the admin/POS exclusion changes, update here first and check understand-your-conversion-data.md for consistency. The two verbatim callouts (beta note, no-card note) are standardized across the collection — keep wording in sync. */}
# Access codes & scheduling
This page explains **when** a booking's door code is active, and the two ways OpenCourt can schedule codes onto
your locks. Most clubs never need to change anything here — but if you run a high volume of bookings, or use
locks that store only a limited number of codes, it's worth understanding.
When is a door code active? [#when-is-a-door-code-active]
Every booking's code is **time-limited**, no matter which provider or scheduling mode you use. By default:
* It becomes active **30 minutes before** the reservation start time.
* It expires **10 minutes after** the reservation end time.
* Outside that window the code does nothing — a customer can't get in early or stay late on it.
The window follows each lock's access rule, so you can change it per lock: the **min before / min after**
values on the lock's *During reservations only* rule set both the unlock window and the code window. See
[Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors). The exact window for every issued code
is shown in the **Access Codes** table (**Valid From** / **Valid Until**).
Scheduling modes: when the code reaches the lock [#scheduling-modes-when-the-code-reaches-the-lock]
"Scheduling" is about *when the code is pushed onto the physical lock*, which matters because most locks can
only store a limited number of codes at once.
| | **Native Scheduling** (default) | **Just-in-Time Scheduling** |
| -------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------- |
| Code pushed to the lock | **72 hours** before it activates | **60 minutes** before it activates |
| Reliability | Highest — the code is on the lock well ahead of time | High — but the lock must be online shortly before each booking |
| Codes stored on the lock at once | More (can hit the lock's limit) | Far fewer |
| Best for | Clubs with fewer upcoming bookings | High-volume clubs, or locks with small code capacity |
Until a code is pushed to the hardware, the Access Codes table may not show its final PIN yet — that's normal.
The PIN appears once the lock accepts it.
Some keypad locks store only a few dozen codes at a time — **Lockly** models are the ones clubs hit this with
most often. A busy club booking many spaces days in advance can exceed that on Native Scheduling, and the lock
starts rejecting new codes.
How do I switch scheduling modes? [#how-do-i-switch-scheduling-modes]
Go to **Settings → Access Controls** and find the **Access Code Scheduling** section. Two options:
* **Native Scheduling** — "Codes are pushed to the lock 72 hours before activation. More reliable, but some
devices have low code capacity limits which can cause issues with high reservation volume."
* **Just-in-Time Scheduling** — "Codes are pushed to the lock 60 minutes before activation. Avoids device
capacity limits, but requires the lock to have internet connectivity before each reservation."
Scheduling controls **when the code is pushed to the lock**, not when it works. The active window — how long
before a booking a code starts working and how long after it stops — comes from each lock's access rule
(30 min before / 10 min after by default). See
[Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors).
The Access Code Scheduling section appears for **Seam**-connected clubs. Other providers push codes their own
way — for example, RemoteLock pushes the code and waits for the lock to confirm it, retrying if the lock is
asleep. Until it confirms, the code shows as **pending**; on capacity-limited locks it may hold a code back
until closer to the booking. That's normal, not a fault.
When to switch to Just-in-Time [#when-to-switch-to-just-in-time]
Consider Just-in-Time Scheduling if any of these is true:
* Customers report codes that **don't work**, or your team sees `access_code.failed_to_set_on_device` errors.
* Your club has a **high volume of upcoming bookings** relative to what your lock can store.
* You use **Lockly** locks (or others with limited code capacity).
* Your locks have **reliable internet** (Just-in-Time needs the lock online about an hour before each booking).
If something goes wrong [#if-something-goes-wrong]
* **Codes intermittently fail on a busy lock** — you're likely hitting the lock's code-storage limit on Native
Scheduling. Switch to Just-in-Time in **Access Code Scheduling**.
* **A code didn't work right at the booking start** — codes activate **30 minutes before** the start by
default, and on Just-in-Time the lock must have been online about an hour earlier to receive it. Check the
lock's connectivity, then work through
[A customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
* **A far-future booking shows no PIN yet** — expected. The PIN appears once the code is pushed to the lock
(about 72 hours ahead on Native, about an hour ahead on Just-in-Time).
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Door codes day-to-day](/help/facility-operators/access-controls/door-codes-day-to-day)
* [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
# Which locks work with OpenCourt
OpenCourt gives each booking its own **door code** and, on supported hardware, an **in-app unlock** button —
through four provider integrations: **Seam**, **RemoteLock**, **Rhombus**, and **UniFi Access**. The lock you
have decides which provider you use, and a club runs **one provider at a time**. This page tells you what
OpenCourt can do with each brand, so you can check a model before you commit to it.
Not sure about a model? Send the exact model to
[support@getopencourt.com](mailto:support@getopencourt.com) and we'll confirm what your lock or access
control system supports — **PIN door codes**, **in-app unlock**, **NFC/BLE proximity keys**, or a combination.
The two multi-brand platforms [#the-two-multi-brand-platforms]
**Seam** and **RemoteLock** each sit in front of dozens of lock brands. Neither is better than the other for
OpenCourt — both connect the same way (sign in to the account you already have), and both give you door codes
and in-app unlock. **If you already have an account with one of them, use that one.**
Each platform keeps its own list of exactly which models it supports, and those lists change. We link to them
rather than copying them, so you're always reading the current one.
RemoteLock [#remotelock]
Its own hardware — **33Lock IntelliBolt / IntelliLever / IntelliMortise** (formerly branded openEDGE) — has
WiFi built in with no separate gateway.
It also manages third-party locks from **Schlage**, **Yale**, **Kwikset**, **August**, **igloohome**,
**KeyInCode**, **Alfred**, **Dormakaba**, **McGrath**, **PROLOK**, **TrueSecure**, **UniKey**, **KoreLock**
and **TTLock**, plus hubs (**Aeotec**, **SmartThings**) and wired access-control doors —
electric strikes and maglocks on **Mercury** panels, **HID** readers (RPK40, Signo), **Allegion**, **ZKTeco
Atlas** and **Rosslare**.
Check a model on [RemoteLock's device finder](https://remotelock.com/find-your-device).
Seam [#seam]
Covers **August**, **Yale**, **Schlage**, **Kwikset**, **Lockly**, **TTLock** (and rebrands such as Sifely),
**igloohome**, **Nuki**, **Wyze**, **2N**, **Akiles**, **Tedee**, **4SUITES**, **33 Lock**, **SmartThings**
(as the hub path for Z-Wave locks), **PTI Storlogix** and **Latch**.
It also reaches professional access-control systems — **Salto KS**, **Brivo**, and **Avigilon Alta**
(formerly Openpath).
Check a model on [Seam's supported devices list](https://docs.seam.co/latest/device-and-system-integration-guides).
**Being listed by Seam is not the same as working with OpenCourt.** Seam's public list and API include
brands at **beta** stage, and beta integrations aren't available to us — only ones marked live. On top of
that, some live ones give OpenCourt nothing to work with (see the section further down). **Always send us the
exact model before you buy**, rather than reading a brand name off Seam's site and assuming.
The two single-system integrations [#the-two-single-system-integrations]
Pick these when you already run that system at your venue.
* **Rhombus** — doors you manage at console.rhombus.com. **Unlock-only**: it never issues door codes. See
[Connect Rhombus](/help/facility-operators/access-controls/connect-rhombus).
* **UniFi Access** — Ubiquiti gear on your own console. See [Connect UniFi Access](/help/facility-operators/access-controls/connect-unifi).
With UniFi Access, four things have to be true, and each one catches someone out:
* **A console that can actually run UniFi Access.** Not all UniFi consoles can, and the one you already own may
not. As of August 2026 that list is the Dream Machine range, **UDR7**, **UDR**, **UCG-Max**, **UCG-Fiber**,
**CloudKey+** and the NVRs. Ubiquiti keeps the current list at [UniFi Consoles with UniFi Access
Support](https://help.ui.com/hc/en-us/articles/22230509487639-UniFi-Consoles-with-UniFi-Access-Support).
If yours can't, adding a **CloudKey+** or an NVR beside it is usually cheaper than replacing the gateway.
* **A PIN-capable reader.** Only some UniFi readers accept codes, and the names are close enough to be
dangerous. **G6 Pro Entry** takes a PIN; **G6 Entry** doesn't. **Access Ultra** doesn't either, despite
being the all-in-one that looks like the obvious single-door pick. Full table in
[Connect UniFi Access](/help/facility-operators/access-controls/connect-unifi).
* **An Access Control Hub behind that reader.** A camera-style reader wired to the network but not to a hub
adopts into UniFi *Protect* and never appears in UniFi *Access* — so OpenCourt can't see the door at all,
and no reader can unlock anything without a hub. A **Door Hub Mini** covers a single door.
* **A console reachable from the internet** (Cloudflare Tunnel or a port-forward on 12445).
**And one thing that must NOT be true: the console must not be enrolled in UniFi Identity Enterprise** (UID
Enterprise). That mode switches off the local Access API, and OpenCourt cannot connect to such a console at
all — there is no workaround. Standard UniFi Access is what you want, so raise it with your installer **before**
the console is set up.
Professional access-control systems [#professional-access-control-systems]
If you already run a commercial access-control system, what OpenCourt can do with it varies:
| System | Door codes | In-app unlock | NFC/BLE proximity keys |
| ------------------------------------- | ---------------------- | ------------- | --------------------------------------------------------------------------------------------------- |
| **Salto KS** | Yes | Yes | Yes — see [Salto KS mobile access](/help/facility-operators/access-controls/salto-ks-mobile-access) |
| **Brivo** | Yes, on keypad readers | — | — |
| **Avigilon Alta** (formerly Openpath) | — | Yes | — |
| **Rhombus** | — | Yes | — |
| **UniFi Access** | Yes | Yes | — |
**Integration coming soon:** [Kisi](/help/facility-operators/access-controls/kisi-access-control) — we're building this one directly.
Supported by the platform, but not usable by OpenCourt [#supported-by-the-platform-but-not-usable-by-opencourt]
A few systems appear on Seam's list yet give OpenCourt nothing to work with. If you run one of these, the
connection will succeed but no door codes or in-app unlock will appear:
* **ASSA ABLOY Visionline** and **ASSA ABLOY Credential Services** — card and mobile credentials only.
* **Salto ProAccess Space** — card and mobile credentials only. (Salto **KS** is different, and does work —
see [Salto KS mobile access](/help/facility-operators/access-controls/salto-ks-mobile-access).)
* **dormakaba Oracode** — precomputed offline codes, not pushed online, so OpenCourt can't issue per-booking
PINs.
Talk to us before planning around any of these.
Both platforms also connect **thermostats** (ecobee, Honeywell/Resideo on RemoteLock; those plus Nest and
others on Seam), and Seam adds **noise sensors**. OpenCourt doesn't use either today —
[**thermostat control**](/help/facility-operators/access-controls/thermostat-control) is something we're working on, so if that's interesting
for your club, let us know and we'll keep you posted.
What decides whether a lock works [#what-decides-whether-a-lock-works]
Three things, and they're the same on every platform:
* **A keypad**, if you want booking door codes. No keypad, no code — there's nowhere to type it.
* **Being online.** OpenCourt can only reach a lock the platform can reach. Some models need the brand's own
bridge or hub to get there; the vendor's product page will say.
* **Enough code storage**, if you book heavily. Locks vary in how many codes they hold at once. If yours is
tight, switch that lock to [Just-in-Time scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling) — that's exactly what
it's for.
Beyond that, ask the vendor or your installer. We can't tell you which model is better built or how many codes
it holds, and we'd rather say so than guess.
What clubs commonly connect [#what-clubs-commonly-connect]
For context rather than as a recommendation — these are the shapes we see most often:
* **1–3 doors, standard entry** — a WiFi keypad deadbolt or lever from either platform's list. No hub needed,
quick to connect.
* **Commercial doors or high booking volume** — RemoteLock's own 33Lock hardware, or UniFi Access with a
PIN-capable reader on an Access Control Hub.
* **Gates, maglocks, or wired entry** — a wired system, such as RemoteLock's ACS kits or UniFi Access.
⚠️ Non-door entry points (vehicle gates, intercoms, turnstiles) vary a lot in what they expose — **check the
specific model with us before planning around one**, rather than assuming it behaves like a door.
"I have nothing yet — what do I actually buy?" [#i-have-nothing-yet--what-do-i-actually-buy]
The most common question on sales and onboarding calls. The honest answer: **start with an installer, not with
a product page.** Any access-control or security installation firm will help you more than this article can.
They'll look at your actual doors — how they're hung, whether they're fire-rated, where power and network
already run, what your local egress code requires — and none of that is visible from here.
Where to find one:
* **Any local access-control or security installer.** The most useful option for most clubs, and the one to
start with. Tell them you need booking codes on the door and that the system has to expose an API.
* **For UniFi** — use Ubiquiti's own directory of certified installers at
[installers.ui.com](https://installers.ui.com/). Worth insisting on someone who has done **UniFi Access**
specifically, not only UniFi networking; they're different products and the second doesn't imply the first.
* **For RemoteLock** — email [partnersales@remotelock.com](mailto:partnersales@remotelock.com) with the
subject **"OpenCourt customer - help choosing lock"**. They'll help you pick hardware and point you at a
dealer in your area.
**Then send us the model they recommend**, before anything is ordered. Confirming it works with OpenCourt takes
us a minute and is worth doing every time, because the same brand often sells both a supported and an
unsupported variant of what looks like one product.
What to expect that conversation to cover [#what-to-expect-that-conversation-to-cover]
Not a shopping list — you're not buying this yourself — but knowing the shape of it makes the conversation much
easier. For **one staffed door with member-only hours** (a small indoor golf or racquet venue, the most common
case), a wired system is three things:
| | What it does | Roughly |
| -------------------------- | ---------------------------------------------------------------- | -------------------------------------------- |
| Access Control Hub | Drives the lock, and is what makes the door visible to OpenCourt | one per door — the Mini covers a single door |
| PIN-capable reader | Where the member types their booking code | one per door |
| Electric strike or maglock | The actual lock | one per door |
Three items, not one. **The mistake people make is buying only the reader** — it's the visible part, so it
feels like the product, but without a hub it can't open anything and OpenCourt can't see it.
There is a simpler path for a single door: if you already run a smart lock at home (August, Yale, Schlage,
Kwikset), one WiFi keypad lock from either platform's list works and skips the hub entirely. It's less robust
for a busy commercial entrance, which is exactly the sort of trade-off an installer is there to weigh.
Before you buy [#before-you-buy]
**Ask us** — send the exact model to [support@getopencourt.com](mailto:support@getopencourt.com) and we'll
confirm:
* Whether it accepts **PIN door codes** from OpenCourt.
* Whether it supports **in-app unlock**.
* Whether **NFC/BLE proximity keys** are available on it.
**Ask the vendor or your installer** — build grade, weather and traffic durability, whether it fits your door,
whether it needs a bridge or hub, and how many codes it holds at once. If that capacity turns out to be low,
you can switch the lock to [Just-in-Time scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling) yourself under
**Settings → Access Controls**.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [Connect RemoteLock to your club](/help/facility-operators/access-controls/connect-remotelock)
* [Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [Kisi access control (coming soon)](/help/facility-operators/access-controls/kisi-access-control)
* [Thermostat control (coming soon)](/help/facility-operators/access-controls/thermostat-control)
# Connect a Seam lock to your club
Connect your club's smart locks through **Seam** so bookings get automatic door codes. *(About 5 minutes.
You'll need admin access and a Seam-supported lock that's online.)*
You need access-control permission. The page is under **Settings → Access Controls**.
Before you begin [#before-you-begin]
* Your lock is a model OpenCourt supports through Seam (for example August, Yale, Schlage, Kwikset, or Lockly)
and it's **online**. Haven't bought one yet? Start with
[Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club), and
[contact OpenCourt support](mailto:support@getopencourt.com) to confirm the model before installing.
* You have the login for the lock's own account (for example your August or Yale account) — you'll sign in to
it during the connection.
Steps [#steps]
1. In the admin app, go to **Settings → Access Controls**. You land on the **Locks** tab. With nothing
connected yet you'll see **No access control system connected**.
2. Click **Connect a provider**. The button expands in place into the systems OpenCourt supports.
3. Choose **Seam**. OpenCourt takes you to Seam's secure connect page.
4. There, choose your lock brand, **sign in to your lock account**, and approve access for OpenCourt.
5. When you're done, you're returned to the **Access Controls** page with your locks listed.
Each lock card shows its name and model, whether it's **Online**, whether it's currently **Locked** or
**Unlocked**, battery level, and badges for **Remote Unlock** and **Access Codes** — what that lock supports.
6. **Map each lock to a space.** Switch to the **Settings** tab and find **Court-to-Lock Mapping** — that
heading follows your club's own wording, so it reads *Bay-to-Lock* or *Field-to-Lock* where that applies.
Choose a lock for each space, then click **Save**. A booking on a mapped space automatically receives a
time-limited door code.
What happens next [#what-happens-next]
Customers who book a mapped space get their own door code for the booking window — you don't issue or revoke
anything. Open a lock to see its assigned codes and recent activity.
A couple of settings worth knowing (both under **Settings → Access Controls**):
* **Let customers unlock from the app** — turn this on so customers can open a mapped door from the OpenCourt
app during their booking. See [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app).
* **Scheduling** — if your club runs a high volume of bookings, or your locks store a limited number of codes,
read [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling) before going live.
If something goes wrong [#if-something-goes-wrong]
* **No locks appear after connecting** — the locks may be offline or not yet added in your lock account. Add or
power them on in your lock's own app, then return to **Access Controls** and refresh.
* **A customer says their code didn't work** — by default, codes activate **30 minutes before** the booking
starts (not earlier) and expire **10 minutes after** it ends. Check the booking time and that the lock is
online, then see [A customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
* **Codes intermittently fail to appear on a lock** — the lock may be at its code-storage limit. See
[Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling) and consider Just-in-Time scheduling.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [Salto KS mobile access](/help/facility-operators/access-controls/salto-ks-mobile-access)
* [Connect RemoteLock to your club](/help/facility-operators/access-controls/connect-remotelock)
# Connect RemoteLock to your club
Connect your club's **RemoteLock** account so bookings get automatic door codes, and so you can lock or unlock
doors from the admin app. *(About 2 minutes. You'll need admin access and a RemoteLock account with at least
one online lock.)*
You need access-control permission. The page is under **Settings → Access Controls**.
Before you begin [#before-you-begin]
* You have a **RemoteLock account** with at least one lock that's online.
* You can sign in to that RemoteLock account — you'll approve OpenCourt's access during the connection.
Steps [#steps]
1. In the admin app, go to **Settings → Access Controls**. You land on the **Locks** tab. With nothing
connected yet you'll see **No access control system connected**.
2. Click **Connect a provider**, then choose **RemoteLock**. You're sent to RemoteLock to sign in.
3. **Sign in to RemoteLock and approve access** for OpenCourt.
4. You return to the **Access Controls** page, which now lists the locks found on your account.
You'll see a line like **"RemoteLock connected · 1 lock. Map each to a court in Settings."** — that line uses
your club's own wording, so it reads "bay" or "field" if that's what you book. Each lock card
carries badges for what it supports — **Online**, **PIN codes**, **Remote unlock**.
5. **Map each lock to a space.** Switch to the **Settings** tab and find **Court-to-Lock Mapping** — the
heading follows your club's wording. Choose a lock for each space and click **Save**. A booking on a mapped
space then automatically receives a time-limited door code.
What happens next [#what-happens-next]
Customers who book a mapped space get their own door code for the booking window — RemoteLock generates the code
and programs it onto the lock for you. Open a lock to see its assigned codes and recent activity, and to lock or
unlock the door remotely. On locks that support remote unlock, customers can also unlock a mapped door from the
OpenCourt app during their booking (according to the access rules you set) — see
[Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors).
RemoteLock programs codes onto the lock in the background and confirms once the lock accepts them, retrying
if the lock is asleep. A new code can show as **pending** for a while before it lands — and either way it only
activates for the booking window, not the moment it's created.
If something goes wrong [#if-something-goes-wrong]
* **"We couldn't reach RemoteLock"** — a temporary connection issue. Try again shortly, or reconnect the
integration from the **Access Controls** page.
* **"RemoteLock is connected, but no locks were found"** — add your devices in RemoteLock, then return to
**Access Controls** and refresh.
* **A code is off by a few hours** — door codes follow the **lock's local time zone**. Make sure the lock's time
zone in RemoteLock matches the club's; OpenCourt flags a mismatch on the lock's page.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
# Connect Rhombus to your club
Connect your club's **Rhombus** access-control organization so you can unlock mapped doors from the admin
app, and so your customers can unlock a door from the OpenCourt app during their booking. *(About 2 minutes.
You'll need admin access and a Rhombus API key.)*
You need access-control permission. The page is under **Settings → Access Controls**.
Rhombus is an **unlock-only** integration. It does **not** create per-booking door codes (PINs) the way
Seam and RemoteLock do — instead, people unlock a mapped door from the OpenCourt app. When a door is
unlocked it opens for a few seconds and then relocks itself.
Before you begin [#before-you-begin]
* You have a **Rhombus organization** with at least one access-controlled door set up.
* You have a **Rhombus API key** for that organization. Generate one in the Rhombus console (Settings →
API keys). Treat it like a password — it grants access to your whole Rhombus organization.
Steps [#steps]
1. In the admin app, go to **Settings → Access Controls**. You land on the **Locks** tab. With nothing
connected yet you'll see **No access control system connected**.
2. Click **Connect a provider**, then choose **Rhombus**. The **Connect Rhombus** dialog opens — "Paste an
organization API key from your Rhombus console. We'll validate it, then discover your access-controlled
doors so you can map them to courts."
3. Paste your key into **Rhombus API key** and click **Connect**. OpenCourt validates the key with Rhombus
and, if it's valid, finds your organization's doors. (Your key is stored securely and is never shown again.)
4. You return to the **Access Controls** page, which shows a line like **"Rhombus connected · 1 door. Map each
to a court in Settings."** — that line follows your club's wording. Note the door's badges: **Online** and **Remote unlock**, with no **PIN codes**
badge — that's the unlock-only nature of Rhombus, visible at a glance.
5. **Map each door to a space.** Switch to the **Settings** tab and find **Court-to-Lock Mapping** — the
heading follows your club's wording. Choose a door for each space and click **Save**. This is what tells
OpenCourt which door belongs to which space, so the right people can unlock it.
6. **Choose who can unlock, and when.** Open a door and use its **Door access** section to control who can unlock it
from the app and during which times (for example, only during a booking). See
[Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors).
What happens next [#what-happens-next]
Customers who book a mapped space can unlock that space's door from the OpenCourt app, according to the
access rules you set. You can also unlock any mapped door yourself from its page in the admin app — the door
opens momentarily and then relocks on its own.
If something goes wrong [#if-something-goes-wrong]
* **"Couldn't connect to Rhombus — check the API key"** — the key was rejected or Rhombus couldn't be
reached. Double-check you copied the whole key from the Rhombus console and try again.
* **"Rhombus is connected, but no doors were found"** — add or enable access-controlled doors in Rhombus,
then return to **Access Controls** and refresh.
* **"The lock didn't respond"** when unlocking — a temporary issue reaching the door. Wait a moment and try
again.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
* [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)
* [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
# Connect UniFi Access to your club
{/*
Maintainers: the UniFi-side paths here were walked on live hardware (UDR7, UniFi OS 5.1.19, Access 4.3.3,
2026-08-07). Two things move between Access versions and are worth re-checking when you touch this page:
the API Token location (4.3.3 = Settings → General, bottom of page — no "Advanced" section) and Ubiquiti's
console-compatibility list, which is why that list is dated inline and linked to the source rather than
copied without provenance. Screenshot still to add: OpenCourt's Access Controls page with doors connected.
*/}
Connect your club's **UniFi Access** console so every booking gets its own door code automatically, and so you
and your customers can unlock a mapped door from the OpenCourt app. *(About 5 minutes. You'll need admin
access, your console reachable from the internet, and a scoped UniFi Access API token.)*
**Read this before you buy or configure anything: your console must NOT be enrolled in UniFi Identity
Enterprise.**
UniFi Identity Enterprise (also written **UID Enterprise**) is Ubiquiti's cloud-managed identity mode. **Any
console enrolled in it has the local Access API switched off, and OpenCourt cannot connect to it at all.** This
is not a setting we can work around, and no amount of tunnelling, port-forwarding, or token fiddling changes
it. If your console is enrolled, OpenCourt's connect attempt fails with *"This console runs UniFi Identity
Enterprise, which disables the local API."*
**Use standard UniFi Access.** If a console is already on Identity Enterprise, it has to be moved back to
standalone UniFi Access before it can be connected — so tell your installer this **before** they set the
console up, not after. Undoing it later is far more work than avoiding it.
You need access-control permission. The page is under **Settings → Access Controls**.
What you'll need (and who sets it up) [#what-youll-need-and-who-sets-it-up]
UniFi Access is a **complete access-control system, not a single device** — neither a hub nor a reader alone
will open a door. For one door you'll typically need:
* A **UniFi console that can run the UniFi Access application** — see the warning below, because not every
UniFi console can.
* An **Access Control Hub** — the door controller the reader and lock connect to. Ubiquiti sells several:
**Door Hub**, **Door Hub Mini** (the compact single-door one), **Gate Hub**, **Elevator Hub**, **Enterprise
Access Hub** (up to 8 doors), and **Retrofit Hub**. Pick by application, not by price — a gate needs the Gate
Hub, not a Door Hub.
* A **reader with PIN support** — see the table below. **This is the one choice that decides whether booking
codes work at all**, so don't let it be made on price.
* An **electric lock or strike**, plus the usual door hardware.
* **Networking** — the hubs and readers are PoE-powered, and some hubs need the higher **PoE++** standard rather
than ordinary PoE, so a suitable switch or injector may be required. Your installer will size this; you don't
need to work it out yourself.
* A way for OpenCourt to reach the console (the next section).
**Not every UniFi console can run UniFi Access — check yours before you buy hardware.** This catches people
out because the console is usually already installed, and the Access application simply isn't offered on it.
**As of August 2026, Ubiquiti lists these as compatible:** Dream Machine Pro (UDM-Pro), Dream Machine Special
Edition (UDM-SE), Dream Machine Pro Max (UDM-Pro-Max), Dream Wall (UDW), Dream Router 7 (UDR7), Dream Router
(UDR), Cloud Gateway Max (UCG-Max), Cloud Gateway Fiber (UCG-Fiber), CloudKey+ (UCK-G2-PLUS), Network Video
Recorder (UNVR), NVR Pro (UNVR-Pro), and Enterprise NVR (ENVR).
Ubiquiti maintains this list and it changes as new hardware ships, so treat the version on their site as
authoritative: **[UniFi Consoles with UniFi Access
Support](https://help.ui.com/hc/en-us/articles/22230509487639-UniFi-Consoles-with-UniFi-Access-Support)**.
**You may not need to replace your gateway.** Ubiquiti's own guidance is to add a supplementary console — a
CloudKey+ or an NVR — alongside the one you have, and let it run Access. Site Manager still manages everything
together.
**Your installer should set up the UniFi Access application and the door itself.** That means installing the
Access application on the console, adopting the hub and reader, creating the door, and wiring the lock. It's
routine work for anyone who does UniFi installs, and we don't document it here — Ubiquiti's [Getting Started
with UniFi Access](https://help.ui.com/hc/en-us/articles/17452334269975-Getting-Started-with-UniFi-Access) is
the reference to hand them.
**You'll know that part is finished when the door appears in UniFi Access showing a status of `Locked`.** That's
the point to come back to this guide.
Which UniFi readers accept booking codes [#which-unifi-readers-accept-booking-codes]
**Booking codes require a PIN-capable reader. This is a hardware decision, and it cannot be fixed in software
later.** Several UniFi readers have no keypad at all, and a reader without a keypad can never accept a booking
code — there is nowhere to type it.
**OpenCourt cannot detect which reader you installed.** Every UniFi door reports itself as able to take codes,
so if the reader has no keypad, OpenCourt will still generate a code for each booking and your customers will
simply have no way to enter it. Nothing will look broken until a customer is standing at the door.
**Check the model against the table below before you order.** If a non-PIN reader is already installed,
OpenCourt can still unlock the door from the app — but per-booking codes won't work until the reader is
replaced.
| Accepts PIN codes ✅ | No PIN ❌ |
| ----------------------------- | --------------------- |
| G6 Pro Entry | **G6 Entry** |
| G3 Reader Pro · G2 Reader Pro | G3 Reader · G2 Reader |
| G3 Reader Fingerprint | **Access Ultra** |
| Reader Flex | Reader Lite |
| Intercom · G3 Intercom | Retrofit Reader |
| Retrofit Reader Fingerprint | — |
**Two model names catch people out.**
* **G6 Entry and G6 Pro Entry are not the same device.** Only the **Pro** accepts PIN codes. The names differ
by one word and the price differs by a lot less than you'd expect — check the model before you buy.
* **Access Ultra is an integrated hub and reader, and it still has no PIN.** It looks like the tidy all-in-one
choice for a single door, and it will never accept a booking code.
**A reader on its own does nothing — it has to be wired to an Access Control Hub.** Ubiquiti requires the
reader to connect **directly to the hub** (same VLAN, Layer-2 Ethernet). Without a hub, a camera-style reader
like the G6 Pro Entry is adopted into **UniFi Protect** only and never appears in **UniFi Access** — which is
the application OpenCourt talks to, so we can't see the door at all. The hub is also the only part of the
chain with a relay to actually throw the lock.
Recent Access versions (3.2.42 and later) do let a non-camera reader run from a plain PoE switch, and it will
show up in UniFi Access that way — but door unlocking isn't supported in that state, so it still gives
OpenCourt nothing to work with.
If you already own a reader and no hub, that's a small addition rather than a redo — a **Door Hub Mini**
covers a single door. It does mean re-running the reader's Ethernet to the hub, so it's an installer visit,
not a settings change.
**OpenCourt doesn't spec, supply, or install the UniFi hardware** — that's the UniFi side. If you're new to
UniFi Access, work with a **UniFi/Ubiquiti installer or IT person**; it's straightforward for anyone who does
this regularly. We'll happily share these guides with them, but the install itself is on your side.
How OpenCourt reaches your console [#how-opencourt-reaches-your-console]
UniFi Access runs **entirely on your own console** — there is no UniFi cloud for door control. So unlike Seam or
RemoteLock, where you just sign in to an account, something has to give OpenCourt a route to a box sitting in your
building. **Sort this out before you connect**, because it produces the address you'll paste in later.
There are two supported ways. **We recommend a port-forward**, and the reason is reliability rather than
convenience: it adds nothing to your building that can quietly stop working.
| | **Port-forward** ✅ recommended | **Cloudflare Tunnel** |
| ----------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **What it is** | Open port `12445` on your firewall, pointing at the console | A helper program makes an outbound-only connection to Cloudflare |
| **Setup time** | \~10 minutes | \~30 minutes, one time |
| **You need** | A **static IP** from your ISP, or **DDNS** (built into UniFi) | A Cloudflare account, a domain hosted on Cloudflare, **and a computer that is always on** |
| **Extra equipment** | **None** | An always-on device — a NAS running Docker, a mini-PC, a Raspberry Pi |
| **Open inbound ports** | Yes — port 12445 | None |
| **Works behind CGNAT** | ❌ No | ✅ Yes |
| **Your installer already knows it** | Almost certainly | Often not |
Why we recommend the port-forward [#why-we-recommend-the-port-forward]
**It adds no new hardware, no third-party account, and no software that has to keep running.** Once the rule is in
place, the only things that need to stay up are your internet connection and the console itself — and if either of
those is down, your club has bigger problems than door codes.
A tunnel needs **a computer that is powered on and running the helper program at all times**. That machine becomes
a part of your access-control system that nobody thinks of as part of your access-control system. When it reboots
without restarting the helper, or its drive wears out, or an update stops the container, **door codes stop and
nothing appears to have changed.** That is a much harder problem to spot than a firewall rule someone edited.
**A tunnel cannot run on the UniFi console itself.** UniFi OS firmware updates erase anything installed outside
the supported applications, so an update would silently break door access. It has to be a separate always-on
device.
Choose the Cloudflare Tunnel instead if any of these are true [#choose-the-cloudflare-tunnel-instead-if-any-of-these-are-true]
* **Your ISP uses CGNAT.** Then a port-forward is impossible, not merely inadvisable. This is common on fixed
wireless, mobile broadband and Starlink. **The test:** if your router's WAN address starts `100.64.` through
`100.127.`, or doesn't match what a "what's my IP" search reports, you are behind CGNAT.
* **You can't get a static IP and don't want to rely on DDNS.**
* **Your organisation's IT policy is not to open inbound ports.** Some clubs inside a larger business or a
landlord's network have this rule set for them.
* **You already run an always-on NAS or server and are comfortable maintaining it.** Then the main drawback
largely goes away.
→ **[Make your UniFi console reachable (Cloudflare Tunnel)](/help/facility-operators/access-controls/expose-unifi-console-cloudflare-tunnel)**
Setting up the port-forward [#setting-up-the-port-forward]
Four steps, all on your side. Your installer can do this in about ten minutes.
1. **Give the console a fixed local IP address**, or a DHCP reservation for it. Do this first. If the console's
local address ever changes, the forwarding rule points at nothing.
2. **Make your public address stable — a static IP from your ISP, or DDNS.** ⚠️ **Check before you buy anything:**
most business connections already have a *public* address, and what you might need to purchase is a **static**
one so it stops changing. If you already have a static IP, or you're happy with DDNS, there is nothing to buy.
**UniFi has DDNS built in** at **Settings → Internet → your WAN → Dynamic DNS**, which keeps this on your own
equipment with nothing extra to run.
3. **Forward TCP port `12445`** to the console's local IP.
4. **Test it from outside your network before connecting** — use [the token
self-test](#optional-have-your-installer-test-the-token-first) below, run from a phone on cellular rather than
on the club's Wi-Fi. **A rule that works from inside the building proves nothing.**
**Steps 1 and 2 are what keep this working for years.** Nearly every port-forward that fails later does so
because the console's local IP moved or the club's public IP changed. Both are one-time settings.
**Keep your API token private.** With a port-forward, the token is what authorises access to your console, so
treat it the way you'd treat a key: don't share it, don't reuse it anywhere else, and create a fresh one if it
ever ends up somewhere public. This is the same arrangement businesses use every day for remote access to
equipment on site.
Two easy habits make it stronger: **set your PIN length to 6 digits** (see [What happens
next](#what-happens-next)), and **delete any old tokens** you're no longer using.
Whichever you pick, OpenCourt secures the connection to your console. On a **tunnel** you get a normal verified
certificate. On a **port-forward** your console presents its own self-signed certificate, so OpenCourt records
that certificate's identity the first time it connects and refuses to talk to anything that doesn't match it
afterwards. Nothing for you to configure.
One consequence: **if the console is ever factory reset, it generates a new certificate** and OpenCourt will
stop connecting on purpose. Reconnect on the Access Controls page and it re-records the new one. A normal
firmware update does not do this.
Before you begin [#before-you-begin]
* You have a **UniFi Access console** (for example, a Dream Machine Pro Max) running the **UniFi Access**
application, with at least one door connected through an **Access Control Hub** and a **PIN-capable reader** (see the
table above). Remote unlock only works on a door bound to a hub.
* **Your console is NOT enrolled in UniFi Identity Enterprise.** That mode turns off the local API OpenCourt
connects to. Standard UniFi Access is what you want. (If it's already on Identity Enterprise, you'd need to
move it back to standalone UniFi Access before connecting.)
* **Your console is reachable from the internet**, by either a **port-forward on 12445** or a **Cloudflare
Tunnel** — see [How OpenCourt reaches your console](#how-opencourt-reaches-your-console) above. Either way, you
come out of it with the **Console address** you'll paste in below.
* Your console is running **UniFi Access 1.9.2 or later** — the version that introduced the API OpenCourt uses.
* You have a **scoped UniFi Access API token**. Creating one takes a minute — see the next section.
Create the API token [#create-the-api-token]
**This lives inside the UniFi Access application, not in UniFi Network or UniFi OS.** Several UniFi
applications have their own "Settings → General" page, so make sure **Access** is the selected application at
the top of the console before you start. If your sidebar shows Policies & Schedules, Card Inventory, Touch Pass
and Visitors, you're in the right place.
1. In the console, open the **Access** application, then go to **Settings → General**.
2. Scroll to the **bottom of the page**. **API Token** is the last row, below Data Retention and Network. Click
**Create New**.
> \[!TIP]
> **There's no "Advanced" section to look for** — the token sits directly at the foot of the **General** page.
> Older Access versions placed it under **Settings → Security → Advanced**, so check there if your console is
> behind.
3. Fill in the dialog:
The screenshot above shows the finished state — **Never Expire**, and **Webhooks on `Edit`**. Everything else
is exactly as the dialog opened.
| Field | What to set |
| ------------------- | --------------------------------------------------------------------------------- |
| **Name** | Anything you'll recognise later — **`OpenCourt Integration`** is a good choice. |
| **Validity Period** | **Never Expire.** See the warning below — this one matters. |
| **Permissions** | **Leave every row at its default, then change `Webhooks` from `None` to `Edit`.** |
4. Click **Create**, then **copy the token immediately** — see the warning below.
About those permissions [#about-those-permissions]
The dialog opens with sensible defaults, and **`Webhooks` is the only one you have to change.** It defaults to
`None`, and OpenCourt uses it to receive door events from your console, so the connection won't work without it.
For reference, this is what OpenCourt actually uses each one for:
| Permission | Needed? | Why |
| ------------------- | --------------------- | ----------------------------------------------------------------------------- |
| **People & Groups** | Default (Edit) | Bookings are added as time-limited visitors alongside your own people. |
| **Visitor** | Default (Edit) | Each booking becomes a visitor, valid only for its time window, then removed. |
| **Access Policy** | Default (Edit) | Scopes each booking's access to the right door. |
| **Credentials** | Default (Edit) | Issues and revokes the booking's PIN code. |
| **Locations** | Default (Edit) | Reads your doors so they appear in OpenCourt, and unlocks them on request. |
| **Device** | Default (View) | Reads hub and reader status. |
| **System Log** | Default (View) | Not used by OpenCourt. Harmless to leave as-is. |
| **Webhooks** | ⚠️ **Change to Edit** | Door events. **Defaults to `None` — this is the one to change.** |
| **API Server** | Default (None) | Not used by OpenCourt. Leave it off. |
**Set Validity Period to `Never Expire`.** If you pick a fixed period, the token silently stops working when it
ends — and the first sign is a customer standing at a door their code no longer opens, weeks or months after
everything was set up correctly. Nothing warns you beforehand.
If your security policy won't allow a non-expiring token, that's fine — but **write the expiry date in your
calendar with a reminder a week ahead**, and reconnect with a fresh token before it lapses.
**UniFi shows the token only once.** Copy it before you close the dialog, and paste it somewhere safe. If you
lose it you can't retrieve it — you'll have to delete it and create another.
Optional: have your installer test the token first [#optional-have-your-installer-test-the-token-first]
This is worth 30 seconds, because it tells you **which side a problem is on** before you involve anyone. Your
installer runs it from any computer on the same network as the console, replacing the address and the token:
```bash
curl -i -k 'https://CONSOLE-IP:12445/api/v1/developer/users' \
-H 'Authorization: Bearer YOUR_TOKEN'
```
* **`"code": "SUCCESS"` with a list of users** — the console, the API and the token are all good. Any later failure
is about reachability from the internet, not about UniFi.
* **`HTTP 401` with `CODE_UNAUTHORIZED`** — the token is wrong, was deleted, or has expired. Create a new one.
* **Nothing connects at all** — UniFi Access isn't installed on that console, or the address or port is wrong.
**`HTTP 200` on its own does not mean success — read the `code` field.** UniFi returns `HTTP 200` for most
failures and puts the real result in the response body. A bad token is the exception and does return a genuine
`401`, but almost everything else arrives as `HTTP 200` with a `code` other than `SUCCESS`, for example:
```
HTTP 200 \{"code": "CODE_USER_WORKER_NOT_EXISTS", "msg": "User not found."\}
```
**So the test to apply is `"code": "SUCCESS"`, never the HTTP status.** This trips up almost everyone
troubleshooting the UniFi API for the first time.
The `-k` is expected and correct. The console presents its own self-signed certificate on port 12445, which is
normal for local UniFi Access, and OpenCourt handles that certificate properly when it connects.
Run the same test from outside the club (port-forward only) [#run-the-same-test-from-outside-the-club-port-forward-only]
Once the forward is in place, repeat the command **using your public address and from a connection that is not the
club's Wi-Fi** — a phone hotspot works:
```bash
curl -i -k 'https://your-host.example.com:12445/api/v1/developer/users' \
-H 'Authorization: Bearer YOUR_TOKEN'
```
**This is the check that matters.** A forward that works from inside the building proves nothing at all, because
traffic never leaves your network. If this succeeds, OpenCourt can reach your console.
Steps [#steps]
1. In the admin app, go to **Settings → Access Controls**. You land on the **Locks** tab. With nothing
connected yet you'll see **No access control system connected**.
2. Click **Connect a provider**, then choose **UniFi Access**. A dialog opens.
3. Under **How is the console reached?**, pick the one that matches what you actually set up — **Direct /
port-forward (recommended)** or **Cloudflare Tunnel**.
> \[!NOTE]
> **Pick the one you built, not the one marked recommended.** Choosing the wrong option here is the most common
> reason a correct address and a valid token still fail to connect, because the two verify your console's
> certificate in different ways.
4. In **Console address**, paste your console's address. For a port-forward that's the full address **including
the port** (for example `https://your-host.example.com:12445`); for a tunnel it's just the hostname (for
example `access.yourclub.com`).
5. In **API token**, paste the scoped token you created, then click **Connect**.
The dialog summarises the difference: **Direct / port-forward (recommended)** — "Port 12445 forwarded to the
console. Nothing extra to run" — versus **Cloudflare Tunnel** — "no open ports. Needs an always-on device
running the tunnel helper."
6. OpenCourt validates the token against your console, sets up push notifications for door events, and discovers
your doors. You return to the **Access Controls** page, which now shows **UniFi Access connected** and the
doors it found.
7. **Map each door to a space.** Switch to the **Settings** tab and find **Court-to-Lock Mapping** — the
heading follows your club's wording. Choose a door for each space and click **Save**. This is what tells
OpenCourt which door belongs to which space, so the right codes and unlock permissions apply.
> \[!TIP]
> **The door names in this list come straight from UniFi, and they're longer than what your installer typed.**
> UniFi builds each label as *console name → floor or location → door name*, so a door someone named
> `OpenCourt Door` shows up here as `Dream Router 7 - 1F - OpenCourt Door`.
>
> Two things follow from that. **Name doors after the space they serve** — `Bay 1`, `Court 3`,
> `Front Entrance` — never leaving a default like `Door c84b`. And **name your floors and locations in UniFi
> sensibly too**, because they appear in every label here and are what tells two similar doors apart.
>
> Renaming a door in UniFi later is safe and the mapping survives. **Deleting a door and recreating it is
> not** — the new one has to be mapped again.
8. **Choose who can unlock, and when.** Open a door and use its **Door access** section to control who can unlock it from
the app and during which times. See [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors).
What happens next [#what-happens-next]
When a customer books a mapped space, OpenCourt creates a **door code** on your console that works only for that
booking's time window, then removes it afterward — nothing to hand out or revoke. On doors bound to a hub, you
can also unlock a mapped door yourself from its page in the admin app, and customers can unlock from the
OpenCourt app during their booking (according to the access rules you set). The door opens momentarily and then
relocks on its own.
**Set your PIN length to 6 digits — UniFi defaults to 4.**
**Your console decides how long the codes are, not OpenCourt.** The codes are generated by UniFi Access itself,
using the **PIN** setting in **UniFi Access → Settings → General**. Out of the box that's **Fixed Length, 4
Digits** — only 10,000 possible codes, on a door that may be unattended 24/7. Selecting **6 Digits** takes it
to a million and costs your customers two extra taps.
The change applies to codes issued from then on. Codes already out with customers keep working, so it's safe to
change at any time.
Everything OpenCourt creates is **added alongside** your console's own setup — your existing cards, PINs, and
policies keep working exactly as before, and OpenCourt only ever removes the codes it created.
If something goes wrong [#if-something-goes-wrong]
Narrow it down first — three questions [#narrow-it-down-first--three-questions]
Answering these before you check anything saves most of the work:
1. **Is it one customer, or everyone?** One customer is almost always their booking or their code, not your setup.
Everyone means the connection between OpenCourt and your console.
2. **Is it one door, or all doors?** One door points at that door's hardware or its mapping. All doors points at
the console or the connection.
3. **Did anything change?** A new router, an internet outage, a UniFi firmware update, an IT visit, a console
reset. Access control breaks far more often because something else changed than on its own.
The five-minute self-check [#the-five-minute-self-check]
Work down this list. It's ordered by how often each one turns out to be the cause.
1. ✅ **Is the API token still there?** This is the most common cause by far. Open **UniFi Access → Settings →
General** and look at the **API Token** row. **If the token you created for OpenCourt is missing, it was
deleted** — by another admin, by a console restore, or by someone tidying up. If it's listed but shows an
expiry date that has passed, it's dead too. Either way: create a new one (**Never Expire**, and remember
**Webhooks → Edit**), then reconnect in OpenCourt with the new token.
2. ✅ **Is the console online?** Check it in UniFi, or at `unifi.ui.com`. A console that's rebooting for a firmware
update is briefly unreachable and needs nothing from you but a few minutes.
3. ✅ **Is the club's internet up?** Nothing reaches your console without it.
4. ✅ **Does the door still exist in UniFi Access, and is it still bound to its hub?** If the door was deleted and
recreated, it's a *new* door as far as OpenCourt is concerned and needs re-mapping.
5. ✅ **Is the right reachability option still selected in OpenCourt?** If your setup changed from a tunnel to a
port-forward, or the other way, the option in OpenCourt has to change with it.
6. ✅ **Port-forward only — has your public address changed?** Compare what a "what's my IP" search shows against
the Console address saved in OpenCourt. If they differ, that's your answer, and a static IP or DDNS is the
permanent fix.
7. ✅ **Tunnel only — is the always-on device still running the tunnel helper?** Check that the machine is powered
on and the helper is running, and that the tunnel shows **Healthy** in Cloudflare. A machine that rebooted
without restarting the helper is the usual culprit.
**The single most useful test is the [self-test command](#optional-have-your-installer-test-the-token-first)
above, run from outside the club.** It separates "the console and token are fine" from "OpenCourt can't reach
it," which is the fork every other question hangs off. Remember to judge it by `"code": "SUCCESS"`, not by the
HTTP status.
Specific symptoms [#specific-symptoms]
* **"This console runs UniFi Identity Enterprise, which disables the local API"** — the console is enrolled in
UniFi Identity Enterprise, which turns off the local API OpenCourt uses. Move the console back to standalone
UniFi Access, then connect again.
* **"Couldn't connect — check the API token and its scopes"** — the token was rejected. Confirm you copied the
whole token and that it hasn't passed its validity period. **The most common cause is `Webhooks` left at
`None`** — it's the one permission the dialog doesn't grant by default. The
[token self-test](#optional-have-your-installer-test-the-token-first) above tells you in one command whether the
token itself is the problem.
* **It worked for months and then stopped** — check the token's **Validity Period**. A token with a fixed period
stops working the moment it expires, with no warning. Create a new one set to **Never Expire** and reconnect.
* **The Access application isn't offered on your console** — not every UniFi console can run UniFi Access. Check
the compatibility warning above, and note that adding a CloudKey+ or NVR alongside your existing gateway is
usually cheaper than replacing it.
* **Codes are issued but customers can't enter them** — the reader has no keypad. Check its model against the
PIN-capable table above.
* **Can't reach the console** — double-check the address, and confirm the console is online. For a tunnel, make
sure the tunnel is running and the hostname resolves. For a port-forward, check that port **12445** is forwarded
to the console's local IP, and **test from outside your network** — a phone on cellular, not the club's Wi-Fi.
A rule that works from inside the building tells you nothing.
* **It worked, then stopped after an internet outage or a router change (port-forward)** — your public IP probably
changed. That's what a static IP or DDNS prevents. Update the Console address in OpenCourt, then fix the
underlying cause so it doesn't recur.
* **Port-forwarding won't work at all, from anywhere** — you may be behind **CGNAT**, where your ISP shares one
address between customers. Check whether your router's WAN address starts `100.64.`–`100.127.`, or differs from
what a "what's my IP" search shows. If so, ask your ISP for a public IP, or use the
[Cloudflare Tunnel](/help/facility-operators/access-controls/expose-unifi-console-cloudflare-tunnel) instead — it works behind CGNAT.
* **Everything stopped right after the console was factory reset (port-forward)** — expected. The console
generated a new certificate, and OpenCourt deliberately refuses to connect to one it doesn't recognise.
Reconnect on the Access Controls page.
* **A door shows no remote-unlock option** — remote unlock only works on doors bound to an **Access Control
Hub**. Door codes still work on any PIN-capable reader on that hub.
* **A reader you installed doesn't appear in UniFi Access at all** — it isn't wired to an Access Control Hub.
Camera-style readers (G6 Entry / G6 Pro Entry) adopt into UniFi *Protect* without one, which looks like a
working install but leaves the door invisible to UniFi Access, and therefore to OpenCourt.
* **"The lock didn't respond"** when unlocking — a temporary issue reaching the door (offline or busy). Wait a
moment and try again.
* **Codes work, but door activity never appears in OpenCourt** — the token is missing the **Webhooks** permission,
which is the one the dialog leaves at `None`. Codes and unlocking work without it, so everything looks fine
until you notice the history is empty. Create a token with **Webhooks → Edit** and reconnect.
* **A customer's code doesn't work, but everyone else's does** — check the booking is for the space mapped to that
door, and that the customer is trying during their booked window. Codes are created for the booking's time only.
Also confirm they're entering it on a keypad reader, not tapping a card reader.
Still stuck? Send us this [#still-stuck-send-us-this]
If you contact us, these five things let us skip straight to the cause:
1. **Whether it's one customer or everyone**, and **one door or all doors**
2. **What changed recently**, if anything
3. **The output of the self-test command** run from outside the club — with the token itself removed
4. **Your console's UniFi OS and Access version numbers** (Access shows its version at the bottom of its sidebar)
5. **How OpenCourt reaches the console** — port-forward or tunnel
Email [support@getopencourt.com](mailto:support@getopencourt.com). ⚠️ **Never send us your API token** — we don't
need it, and you should replace any token that's been shared.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
* [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app)
* [Make your UniFi console reachable (Cloudflare Tunnel)](/help/facility-operators/access-controls/expose-unifi-console-cloudflare-tunnel)
* [Connect Rhombus to your club](/help/facility-operators/access-controls/connect-rhombus)
* [A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
# Disconnect or switch your lock provider
Disconnect your club's lock provider, or replace it with a different one. *(About 5 minutes. You'll need admin access. Disconnecting revokes every active door code, so pick a quiet time.)*
This lives under **Settings → Access Controls** and needs access-control permission. Your club runs **one** provider at a time — Seam, RemoteLock, Rhombus, or UniFi Access. There's no way to run two at once, so switching means disconnect first, then connect the new one.
Pause codes without disconnecting [#pause-codes-without-disconnecting]
If you only need to stop new codes for a while — a closure, a hardware swap, testing — don't disconnect. Change the **access-control mode** instead. The mode has three options:
* *Off* — "No access codes are used."
* *Manual Access Codes* — you set codes yourself.
* *Smart Lock (\{provider})* — codes are generated automatically.
Switching from *Smart Lock* to *Off* or *Manual Access Codes* shows this confirmation:
> New events and reservations will no longer generate \{provider} access codes. Existing codes on previously created events will remain active. Your \{provider} connection and lock mappings will be preserved if you switch back.
So a mode switch **pauses** code generation but keeps your connection, your lock-to-space mappings, and your per-lock rules. Disconnecting removes all of that. For anything temporary, switch the mode.
Disconnect the integration [#disconnect-the-integration]
1. Go to **Settings → Access Controls** and stay on the **Locks** tab. **Disconnect Integration** sits at the
top right, above your lock cards — not on the Settings tab.
2. Click **Disconnect Integration**. A confirmation opens titled **Disconnect locks integration?** with this text: "This will immediately revoke all active door codes and remove all lock devices. Customers and staff will lose smart lock access until you reconnect a provider. You can reconnect at any time."
3. Click **Disconnect**. You'll see **Locks integration disconnected.** and the page returns to the provider picker: "Choose the access control system your club uses." — listing **Seam**, **RemoteLock**, **Rhombus**, and **UniFi Access**.
What disconnecting removes [#what-disconnecting-removes]
Disconnecting is immediate and clears everything:
* **All active door codes are revoked** and stored codes are deleted — customers and staff lose smart lock access right away.
* **Every lock device and its space mapping is removed.**
* **The provider connection is removed.**
* The action is recorded in your club's activity log.
Reconnecting later means re-mapping locks to spaces and reconfiguring per-lock rules from scratch.
Switch to a different provider [#switch-to-a-different-provider]
1. **Pick a quiet time.** Customers with upcoming bookings lose their codes the moment you disconnect.
2. **Disconnect** the current provider (steps above).
3. **Connect the new provider** from the picker: [Seam](/help/facility-operators/access-controls/connect-a-seam-lock), [RemoteLock](/help/facility-operators/access-controls/connect-remotelock), [Rhombus](/help/facility-operators/access-controls/connect-rhombus), or [UniFi Access](/help/facility-operators/access-controls/connect-unifi).
4. **Re-map each lock to its space** — mappings don't carry over.
5. **Re-set your per-lock rules** (who can unlock, and when).
6. **Test one booking end-to-end** to confirm codes reach the hardware.
**Existing future bookings do not get new codes on their own.** Codes are issued when a booking is created or
changed — connecting a provider and mapping spaces doesn't sweep back over bookings that already exist. So
every booking made *before* the switch is left without a code, silently.
Re-save each affected upcoming booking (opening and saving it re-issues the code), or contact
[OpenCourt support](mailto:support@getopencourt.com) to re-issue them in bulk. If you have more than
a handful, ask us — don't click through them one by one.
If something goes wrong [#if-something-goes-wrong]
* **Disconnect fails or errors** — a temporary connection issue. Try again shortly; if it keeps failing, contact OpenCourt support.
* **Customers report lost door codes after disconnecting** — expected. Disconnecting revokes every active code immediately (see the timing note above). Re-save their bookings or contact support to re-issue codes.
* **You disconnected but only wanted a pause** — reconnect the provider, then re-map locks and rules. Next time, switch the **mode** to *Off* instead — it keeps your connection and mappings.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [Connect RemoteLock to your club](/help/facility-operators/access-controls/connect-remotelock)
* [Connect Rhombus to your club](/help/facility-operators/access-controls/connect-rhombus)
* [Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi)
# Door codes day-to-day: view, share, and manage access codes
Your locks are connected and mapped — this is the day-to-day: where to find any booking's door code, what
the customer already sees, and what happens to a code when a booking is cancelled, rescheduled, or moved.
*(For admins and front desk. No setup needed if your locks are already connected.)*
Access codes live under **Settings → Access Controls** in the admin app, on the **Access Codes** tab. If you
haven't connected a lock yet, start with [How access controls work in OpenCourt](/help/facility-operators/access-controls).
Where do I see a booking's door code? [#where-do-i-see-a-bookings-door-code]
**Front-desk answer first.** Go to the **Access Codes** tab. It lists every code across all your
locks, with a link from each row's **Event** to the booking it belongs to.
There's a search box above the table, so you can type a customer's event name or a code to jump straight to it.
* **Per lock.** Open a lock from the **Locks** tab and scroll to
**Lock Activity** for just that lock's history. A lock with no codes shows *No access codes have been
generated for this lock.*
Each code is created the moment a booking is made on a lock-mapped **space** — your courts, bays, or fields. By default it's active from **30
minutes before** the start to **10 minutes after** the end — if you've customized a lock's access rule, the
window follows that rule instead. The **Status** column tells you where each code stands:
| Status | Meaning |
| ------------ | ------------------------------------------------------------------------------------- |
| **Active** | The code works right now. |
| **Upcoming** | Issued, but its window hasn't started yet. |
| **Expired** | The booking window has passed; the code no longer works. |
| **Revoked** | The code was removed (for example, the booking was cancelled). |
| **Unknown** | OpenCourt can't confirm the code's state on the lock — check that the lock is online. |
On **Native** scheduling, a far-future booking may show a code that isn't on the lock yet — the real PIN
appears once it's pushed (\~72 hours ahead; **Just-in-Time** pushes \~60 minutes ahead). This is expected. See
[Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling).
What does the customer see? [#what-does-the-customer-see]
Sharing is automatic — you don't send codes out. The customer already has theirs:
* **In the app**, on the booking or event details as **Access code**. Before it's usable they see *Access code
will be available at \{time}*. It also appears in their reservations list.
* **In email** — the booking confirmation, event-joined, and event-reminder emails each include a line
**Access Code: \{code}**.
So the front desk only needs the **Access Codes** table for walk-up questions ("what's my code?") — everyone
who booked already received theirs.
What happens when a booking changes? [#what-happens-when-a-booking-changes]
| Change | What happens to the code | What the customer gets |
| ----------------------------------- | -------------------------------------- | ---------------------------------------------- |
| **Cancelled** | Code is revoked. | Their code stops working. |
| **Rescheduled** (same space/door) | **Same PIN**, validity window updates. | No new code to learn. |
| **Moved to a different space/door** | Old code revoked, **new code issued**. | An automatic *Your access code changed* email. |
| **Extended** | **Same PIN**, window extends. | No new code to learn. |
Using manual codes without a smart lock [#using-manual-codes-without-a-smart-lock]
You don't need a smart lock to hand out door codes. Under **Settings → Access Controls**, the access-code mode
has three options:
* **Off** — *No access codes are used.*
* **Manual Access Codes** — *Set access codes manually on events and reservations. A default code can
auto-apply to court bookings.* Pick this and fill the required **Default access code for court bookings**
field (for example *1234*). Every booking then shows that code. (Those labels follow your club's wording —
"bay" or "field" instead of "court" where that applies.)
* **Smart Lock (\{provider})** — the connected-lock behavior described above, with per-booking generated codes.
In **Manual Access Codes** mode, any single event or reservation can override the default in its own **Access
Code** field. Manual codes have **no time window** — they're always shown to participants, not just around the
booking.
Switching away from Smart Lock mode warns: *New events and reservations will no longer generate \{provider}
access codes. Existing codes on previously created events will remain active. Your \{provider} connection and
lock mappings will be preserved if you switch back.* Nothing is lost — you can switch back later.
The activity trail [#the-activity-trail]
* **Per lock.** Each lock's page has a **Lock Activity** section showing the last 2 days by default.
* **Club-wide.** The **Unlock History** tab logs every event with **Date & Time**, **Lock**, **Action**,
**Method**, and **Details**.
* **Club activity log.** **In-app** unlock attempts — successes and failures — also land in the club activity
log with the customer's name, because the customer was signed in when they tapped. Keypad entries can't be
attributed to a person: a door code is shared by everyone on the booking, so it identifies the booking.
Reading the Method column [#reading-the-method-column]
**Method** is the most useful column, because it tells you *how* the door opened — and that determines whether
there's a booking to trace it back to.
| Method | What happened | Can you tie it to a booking? |
| ------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **Keycode** | Someone typed a code on the keypad. | Usually yes — **Details** shows the code and links to the event, e.g. *1027 · Coach-Led Drill Sessions*. |
| **Manual** | The door was operated by hand — a thumb-turn from the inside, a key, or the lock's own button. | No. There's no code involved, so **Details** just reads *Reported by lock*. |
| **Auto-lock** | The lock re-locked itself after its timer. | No — it's the lock's own housekeeping. |
| **Unknown** | The lock reported a change without saying how. | No. |
So a run of **Manual** unlocks isn't a mystery — that's people leaving through the door from inside. When you
need to know *who*, look for **Keycode** rows: those are the ones that carry a code and a linked booking.
Not every Keycode row resolves to a code. If someone typed a code the lock knows but OpenCourt didn't issue —
a staff code you set up directly on the hardware, for example — you'll see **Keycode** with *Reported by lock*
and no link. That's expected, and a useful signal that a non-OpenCourt code is in circulation.
If something goes wrong [#if-something-goes-wrong]
* **A customer says their code doesn't work** — check the row's **Status** and the lock's Lock Activity, then
see [When a customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
* **The code shows but isn't on the lock yet** — this is the Native "not-yet-materialized" case; the deep
triage is in [When a customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
* **The unlock history shows "Access Denied" or "Access Code Failed"** — start the diagnosis in
[When a customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [When a customer can't get in](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
* [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)
# Make your UniFi console reachable (Cloudflare Tunnel)
{/*
Publishing decision (2026-08-01, Alex): ship without screenshots, ahead of the first real UniFi customer.
Steps are written from Cloudflare's CURRENT docs — Networking > Tunnels, then the tunnel's Routes tab >
Add route > Published application. Cloudflare retired the old Zero Trust > Networks nav and the separate
Public Hostnames tab, so any older draft of this page (or guide found online) is stale. NOT walked
end-to-end against a live console. Add dashboard screenshots at the first customer install.
*/}
UniFi Access runs entirely on your own console — there is no UniFi cloud for door control — so OpenCourt needs a
way to reach that console over the internet. **There are two supported ways to provide it, and this guide covers
one of them.** A **Cloudflare Tunnel** works like this: a small helper makes an **outbound-only** connection to
Cloudflare, and Cloudflare gives OpenCourt a normal `https://…` address that points back to your console — **no
ports opened on your firewall, no static IP needed, and it works behind CGNAT**. *(About 30 minutes, one time.)*
**A port-forward is the way we recommend, and it's simpler — read [How OpenCourt reaches your
console](/help/facility-operators/access-controls/connect-unifi#how-opencourt-reaches-your-console) before following this guide.** A port-forward
takes about 10 minutes, adds no extra equipment, and has nothing that can silently stop running. This guide is
the right one only in specific cases.
**Use the tunnel if:** your ISP uses **CGNAT** (a port-forward is then impossible), you can't get a static IP and
don't want to rely on DDNS, your security policy forbids an open inbound port, or you already run an always-on
NAS or server and are happy maintaining it.
⚠️ **The main trade-off:** a tunnel needs **a computer that is always on** running the helper program. If that
machine reboots without restarting it, or its drive fails, **door codes stop working and nothing looks like it
changed.** A port-forward has no such component. Only choose this path if someone will notice when that box goes
down.
This is a networking task, not an everyday admin task, and **OpenCourt doesn't do the install** — if your club
has a **UniFi installer or IT person**, hand it to them; it's quick for anyone who works with UniFi gear.
You're welcome to share this guide with them.
Before you start, make sure the console is **not** enrolled in **UniFi Identity Enterprise** — that mode turns
off the local API OpenCourt connects to, and no amount of tunnelling will get around it. Use standard UniFi
Access. (If it's already on Identity Enterprise, move it back to standalone UniFi Access first.)
Before you begin [#before-you-begin]
* A **Cloudflare account** (the free plan is fine) with a **domain managed in Cloudflare**. If you don't have a
domain on Cloudflare yet, add one — a cheap domain works; you point its nameservers at Cloudflare. Without a
domain in Cloudflare there's nothing to attach the tunnel to.
* One **always-on device on the same network as the console** to run the tunnel helper (`cloudflared`) — a NAS
that runs Docker, a small always-on mini-PC, or a Raspberry Pi. **Don't install it on the UniFi console
itself** — that setup gets wiped by firmware updates. Use a separate little box.
* Your **console's local IP address** (for example `192.168.1.10`), from your UniFi network settings.
Steps [#steps]
1. In the Cloudflare dashboard, go to **Networking → Tunnels** and select **Create Tunnel**. Choose
**Cloudflared**, and give it a name that says what it's for — `opencourt-access` works.
2. Cloudflare shows a **one-line install command with a token**. Run it on your always-on device — pick your
operating system and it generates the exact command; the **Docker** one is usually easiest. Within a few
seconds the tunnel appears on the Tunnels page with a **Healthy** status.
3. Open the tunnel, go to its **Routes** tab, and select **Add route → Published application**. Fill it in
like this:
| Field | Value |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Hostname** | a subdomain plus your Cloudflare domain — for example `access` + `yourclub.com`, giving you `access.yourclub.com` |
| **Service URL** | your console's local address **with port 12445** — for example `https://192.168.1.10:12445` (use your real IP) |
| **TLS → No TLS Verify** | **On**, in the route's additional/origin settings |
**No TLS Verify** matters and it's the step people skip. The UniFi console presents a self-signed
certificate, so without it Cloudflare refuses that last hop and the connection fails. It only affects the
hop *inside your own network* — the tunnel → Cloudflare → OpenCourt path stays fully encrypted, and
OpenCourt verifies the certificate on its end.
4. **Save.** Your console is now reachable at `https://access.yourclub.com`. That hostname is what you paste
into OpenCourt's **Console address** field — choose **Cloudflare Tunnel** as the connection type. Continue
with [Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi).
Cloudflare reorganized this part of its dashboard, and older guides you'll find online say **Zero Trust →
Networks → Tunnels** with a separate **Public Hostnames** tab. If your account still shows that layout, the
settings are identical — it's the same tunnel, just reached a different way.
Keep it running [#keep-it-running]
The little box running the tunnel must **stay powered on**. If it sleeps or loses power, the tunnel drops and
OpenCourt can't sync door codes until it's back — so use an always-on NAS or mini-PC, not a laptop that sleeps.
(A UPS on that device and the console keeps everything online through short power blips.)
The port-forward alternative [#the-port-forward-alternative]
If you'd rather not run a tunnel, you can instead **forward the console's port 12445** to the internet and give
OpenCourt that address (for example `https://your-public-host:12445`), choosing **Direct / port-forward** when
you connect. This needs a **static (or otherwise stable) public IP** so the address OpenCourt connects to doesn't
change. OpenCourt pins the console's certificate on first connect. This works, but it opens a port on your
firewall, so a tunnel is the recommended, safer option.
If something goes wrong [#if-something-goes-wrong]
* **The tunnel shows "Down" or "Degraded" in Cloudflare** — the `cloudflared` helper isn't running. Make sure
the device it's installed on is powered on and the container/service is up, then re-check.
* **OpenCourt says it can't reach the console** — check the route's three settings: the **Service URL starts
with `https://`**, it **ends with `:12445`**, and **No TLS Verify is on**. Those are the usual culprits, and
a missing No TLS Verify is the most common of the three. Also confirm the console itself is online on the
local network.
* **Everything's connected but connect still fails** — double-check the console isn't on **UniFi Identity
Enterprise** (it disables the local API), and that your API token has all the required scopes. See
[Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi#if-something-goes-wrong).
Related [#related]
* [Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi) — the next step, once the console is reachable.
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
# Home Assistant
{/*
Updated 2026-09-28: outbound webhooks now ship (OC-3238, docs/webhooks.md "Outbound"). A club subscribes its own
URL under Settings → API → Webhooks and receives signed `booking.created` / `booking.updated` / `booking.canceled`
POSTs whose `data.object` is the /v1 booking DTO (start, end, spaces[] in club time). The API section is gated
on the club's `api_surface` setting (default hidden), so the copy routes clubs through support to switch it on.
What is still NOT built, and why the page keeps a "what's next" section: there is no timed signal AT a booking's
start or end (no `booking.started` / `booking.ended` in services/SignalService/registry.ts), and no guided Home
Assistant setup. Today HA has to schedule its own automations from the start/end times in the payload.
The "no port forwarding" claim rests on Home Assistant Cloud (Nabu Casa) CLOUDHOOKS — a public https URL that
relays to a local HA webhook trigger. Self-hosted HA without Nabu Casa needs a tunnel, same as UniFi Access.
Deliveries do not carry a signature HA's webhook trigger can check, so the webhook URL itself is the secret.
Direction of control is a deliberate product call (Alex, 2026-08-02): we EMIT booking facts, the club's
automation decides what happens. Do not rewrite this page into "OpenCourt controls your lights".
Vercel is serverless — a persistent WebSocket per club's HA instance is architecturally off the table.
Webhooks and polling are the only viable shapes. Don't let a future draft promise live bidirectional sync.
*/}
**Home Assistant** is open-source home and building automation that runs on a small box at your venue. It
speaks Zigbee, Z-Wave, Matter, Wi-Fi and most things in between, which makes it the usual choice for clubs
that want lights, heating, ventilation and everything else on one system they control. With OpenCourt
**webhooks**, your **bookings** can drive it.
**You can connect Home Assistant today with webhooks.** There's no dedicated Home Assistant setting yet — you
point an OpenCourt webhook at a Home Assistant webhook trigger and build your automations on it.
Why it suits a club that runs unstaffed [#why-it-suits-a-club-that-runs-unstaffed]
A venue open 24/7 with nobody on site has the same problem in every room: the building doesn't know when
anyone is coming. Lights burn all night or a customer walks into a dark bay. Heating runs for an empty
building or the first booking of the day starts cold.
OpenCourt already knows exactly when every space is occupied, because that's the booking calendar — the same
information that issues a door code. Home Assistant already knows how to switch anything you've connected to
it. The integration is the wire between the two.
Your automations stay yours [#your-automations-stay-yours]
The design is deliberate: **OpenCourt sends the facts, your Home Assistant decides what happens.** OpenCourt
tells Home Assistant when a booking is made, changed or canceled, with its spaces and its start and end times.
What that triggers is entirely yours to write.
That matters for three reasons:
* **Home Assistant is better at automation than a booking platform will ever be.** You get its full engine,
not the handful of toggles we'd have built.
* **Nothing is locked to us.** Your automations are yours, in your config, running on your hardware.
* **You set the safety margins.** How long lights stay on after a booking ends, what happens when someone's
still in the building, which circuits are off-limits — those are decisions for the club, not for us.
If you automate anything that cuts power — lighting especially — build in a grace period and a manual
override at the wall. A space can still be occupied after a booking's end time, and no schedule knows that
as well as a person standing in the room.
What clubs ask us for [#what-clubs-ask-us-for]
The kinds of automation this opens up, based on what operators already tell us they want:
* **Lighting** per bay, court or studio, on before arrival and off after the last booking.
* **Heating and cooling**, either through Home Assistant or through our own
[thermostat control](/help/facility-operators/access-controls/thermostat-control).
* **Ventilation and extraction** in enclosed simulator bays.
* **Screens, projectors and audio** powered down overnight.
* **Alarm arming** once the last booking of the day has ended.
We're not promising any specific one of these — what OpenCourt provides is the booking signal. Which
devices respond to it is a question for your Home Assistant setup.
Connect it with webhooks [#connect-it-with-webhooks]
A **webhook** is a message OpenCourt sends to an address you choose each time something changes at your club.
Home Assistant can receive these through a **webhook trigger** in an automation.
1. **Ask us to turn on the API section.** Webhooks live in the OpenCourt API settings, which are off for a club
by default. Email [support@getopencourt.com](mailto:support@getopencourt.com) to switch them on.
2. **Create a webhook trigger in Home Assistant** and copy its address. The address must use `https` and be
reachable from the internet.
3. **In OpenCourt, go to Settings → API → Webhooks** and click **Add endpoint**.
4. **Paste the address into Endpoint URL.** Under **Signals to send**, select `booking.created`,
`booking.updated` and `booking.canceled`. OpenCourt selects the **Bookings** access they need for you.
5. **Click Add endpoint** to save it. The **Webhook deliveries** panel on the same page shows every message sent, and lets
you send a test.
Each message carries the booking's spaces and its start and end times in your club's timezone. Your
automation uses those times to schedule what happens — for example, lights on 10 minutes before the start
time and off 15 minutes after the end time. When a booking moves or is canceled, a new message arrives so
your automation can change or remove what it scheduled.
Anyone who knows a Home Assistant webhook address can call it. Keep the address private, and don't share it
in screenshots or support tickets.
Without opening your firewall [#without-opening-your-firewall]
**Home Assistant Cloud** (Nabu Casa) can give a webhook trigger a public address that forwards to your local
instance — no ports opened, no static IP, no tunnel to maintain. A self-hosted instance with no such address
needs to be reachable another way, in the same shape as
[making a UniFi console reachable](/help/facility-operators/access-controls/expose-unifi-console-cloudflare-tunnel). Home Assistant's own
documentation covers the webhook trigger settings that allow an outside service to call it.
Or poll the API [#or-poll-the-api]
A club comfortable with Home Assistant configuration can also read bookings from OpenCourt's **read-only REST
API**. Its schedule endpoint returns every booking with its spaces and start and end times in your club's
timezone. The API is in preview, so response shapes can still change — worth knowing before you build
something you depend on.
What's next [#whats-next]
Today OpenCourt sends a message when a booking is made, changed or canceled — not at the moment a booking
starts or ends, so Home Assistant does the timing. We're looking at messages sent at the start and end of a
booking, and a simpler setup made for Home Assistant.
Register your interest [#register-your-interest]
Tell us you run Home Assistant and we'll factor your setup into what we build next.
* Email [support@getopencourt.com](mailto:support@getopencourt.com), or
* Talk to your OpenCourt account representative.
Useful things to mention: whether you run Home Assistant Cloud or self-host, what you'd want a booking to
trigger, and whether your venue operates unstaffed.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Thermostat control (coming soon)](/help/facility-operators/access-controls/thermostat-control)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
# How access controls work in OpenCourt (overview)
Access controls connect your club's smart locks to OpenCourt so every booking gets its own **door code**
automatically — and, on supported locks, so customers can unlock the door from the OpenCourt app. This page
explains how it fits together; the linked guides cover each task.
Access controls live under **Settings → Access Controls** and are available to admins with access-control
permission.
What you get [#what-you-get]
* **Automatic door codes.** Map a lock to a **space** (your courts, bays, or fields) and every booking on it
gets a code that works only for that booking's time window, then disappears. Nothing to hand out or revoke.
* **In-app unlock.** When you enable it, customers can unlock a mapped door from the OpenCourt app during their
booking (see [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app)).
* **NFC/BLE proximity keys.** Clubs on a Salto KS access-control system can grant phone-based access — the
customer holds their phone to the reader instead of typing anything.
* **A full activity trail.** Every code, every unlock attempt, and every change is visible in your admin panel.
Everything OpenCourt creates is **added alongside** your lock's existing setup — your staff codes, fobs, and
cards keep working, and OpenCourt only ever removes the codes it created.
Which provider do I connect? [#which-provider-do-i-connect]
You connect **one** provider, and they come in two kinds.
**Multi-brand platforms — Seam and RemoteLock.** Both sit in front of dozens of lock brands, so you connect by
signing in to the account you already have with them. Between them they cover the consumer and light-commercial
locks most clubs buy (August, Yale, Schlage, Kwikset, Lockly and more), and Seam additionally reaches
professional access-control systems: **Salto KS**, **Brivo**, and **Avigilon Alta** (formerly Openpath). If you
already have an account with either platform, use that one.
**Single-system integrations — Rhombus and UniFi Access.** Pick these when you already run that specific system
at your venue: Ubiquiti gear on the wall (Dream Machine, UniFi Access hubs and readers) means **UniFi Access**;
doors managed at console.rhombus.com means **Rhombus**.
| | **Seam** | **RemoteLock** | **Rhombus** | **UniFi Access** |
| ---------------------- | ------------------------------ | ------------------------------ | ----------- | ----------------------- |
| Door codes | Yes, on supported locks (most) | Yes, on supported locks (most) | — | Yes |
| In-app unlock | Yes, on supported locks (most) | Yes, on supported locks (most) | Yes | Yes |
| NFC/BLE proximity keys | Via Salto KS | — | — | — |
| Connect with | Account sign-in | Account sign-in | API key | Console address + token |
A couple of details behind that table: **Rhombus is unlock-only** — it never issues door codes. **RemoteLock and
UniFi Access generate the code themselves** rather than OpenCourt generating it. And on **UniFi Access**, in-app
unlock only works on doors bound to a hub.
UniFi Access runs on **your own console** rather than a vendor cloud, so it needs one extra setup step — making
the console reachable from the internet. See [Connect UniFi Access to your club](/help/facility-operators/access-controls/connect-unifi).
Before you buy a lock, check it works with OpenCourt. See
[Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club), and send us the exact model — we'll
confirm whether it does PIN door codes, in-app unlock, and NFC/BLE proximity keys. Build quality and
installation are questions for the vendor or your installer, not us.
How a door code reaches the lock [#how-a-door-code-reaches-the-lock]
1. You connect a provider and **map each lock to a space**.
2. A customer books that space.
3. OpenCourt creates a code for the booking and schedules it onto the lock.
4. The code activates for the booking window, then is removed.
Codes are **time-limited**: by default they become active **30 minutes before** the reservation starts and
expire **10 minutes after** it ends (each lock's access rule can adjust this). Exactly *when* the code is
loaded onto the hardware depends on your scheduling mode — see
[Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling).
Start here [#start-here]
**Set up**
* **[Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)** — check a model before you buy:
brands and systems, and what each one supports.
* **[Connect a Seam lock](/help/facility-operators/access-controls/connect-a-seam-lock)** — the most common setup.
* **[Connect RemoteLock](/help/facility-operators/access-controls/connect-remotelock)** · **[Connect Rhombus](/help/facility-operators/access-controls/connect-rhombus)** ·
**[Connect UniFi Access](/help/facility-operators/access-controls/connect-unifi)**
* **[Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)** — turn on in-app unlocking and set
per-lock rules for who can unlock and when.
* **[Salto KS mobile access](/help/facility-operators/access-controls/salto-ks-mobile-access)** — phone-based access on a Salto KS system.
**Run it day-to-day**
* **[Door codes day-to-day](/help/facility-operators/access-controls/door-codes-day-to-day)** — look up any booking's code, see what customers see,
and what happens when bookings change.
* **[Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)** — code timing, and Just-in-Time vs Native
scheduling for high-volume clubs.
* **[Home Assistant](/help/facility-operators/access-controls/home-assistant)** — send bookings to Home Assistant with webhooks, so they drive
lights, HVAC and whatever else you automate.
**When something's wrong**
* **[A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)** — the triage
guide for the front desk.
* **[Disconnect or switch your lock provider](/help/facility-operators/access-controls/disconnect-or-switch-lock-providers)** — what disconnecting
does, and how to change systems safely.
**Coming soon**
* **[Kisi access control](/help/facility-operators/access-controls/kisi-access-control)** — an integration we're building for clubs already
running Kisi.
* **[Thermostat control](/help/facility-operators/access-controls/thermostat-control)** — heating and cooling that follows your bookings.
Common questions [#common-questions]
Is every door code unique? [#is-every-door-code-unique]
Yes — every booking gets its own code, and it only works during that booking's window.
The thing to know is that a code belongs to the **booking**, not to one person:
* **A space reservation** gets one code. Whoever booked it and everyone playing with them all see the same code.
* **An event or program** gets one code for that session, which every registered participant sees.
That's deliberate: nobody gets stuck outside because they weren't the one who made the booking. By default a
code works from 30 minutes before until 10 minutes after, following the window your club set on that lock —
outside it, the code does nothing.
What happens if the internet goes down? [#what-happens-if-the-internet-goes-down]
Codes that already reached the lock keep working — they're stored on the lock itself, so customers can still
type them in. New codes can't reach the lock until it's back online, and in-app unlock needs the lock online.
If outages are common at your facility, prefer Native scheduling (codes load \~72 hours ahead) — see
[Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling).
Do our existing keys, fobs, and staff codes keep working? [#do-our-existing-keys-fobs-and-staff-codes-keep-working]
Yes. OpenCourt adds booking codes alongside whatever your lock system already has, and only ever removes the
codes it created.
Can I see which codes were used, and when? [#can-i-see-which-codes-were-used-and-when]
Yes. Every lock has its own activity feed, and the club-wide **Unlock History** logs each door event with the
time, the lock, what happened, and the method.
What it ties back to depends on how they got in:
* **Someone typed a door code** — you see the code and the booking or event it belongs to, like
*1027 · Coach-Led Drill Sessions*. Because that code is shared by everyone on the booking, it identifies the
**booking, not the individual**.
* **Someone unlocked from the app** — they were signed in, so this one is attributable. Your club's activity
log records the attempt by name, successful or not.
* **The door was opened by hand** from the inside, or re-locked on its timer — there's no code involved, so
there's nothing to attribute.
See [Door codes day-to-day](/help/facility-operators/access-controls/door-codes-day-to-day).
Do customers need a separate app for the door? [#do-customers-need-a-separate-app-for-the-door]
No. Codes and in-app unlock live in the same OpenCourt app they book with. The one exception is
NFC/BLE proximity keys (Salto KS), which must use your club's branded app.
# Kisi access control (coming soon)
{/*
This page is a COMING-SOON placeholder published for SEO/AI-search reach (2026-08-02, Alex's call).
Nothing is built: Kisi appears only as a future case in webhookRouter.ts.
Deliberately does NOT promise per-booking keypad PINs: Kisi has no Seam-style typed PIN credential
(two_factor_pin is deprecated and card-bound). The mechanism described here is Kisi's ACCESS LINKS
API, re-verified against docs.kisi.io on 2026-08-02: create a link scoped to a group with a validity
window, pass quick_response_code_type, and the response carries a QR image you can render in your own
app. Two hard constraints kept in the copy: (1) QR scanning needs a Kisi Terminal Pro / QR scanner,
NOT a bare Reader Pro; (2) Kisi's own docs say digital credentials BYPASS geofence and reader-proximity
restrictions and recommend them for short-term / low-security doors — fine for booking-length access,
but a deliberate call to make when this gets scoped. Nothing is built.
*/}
**Kisi** is a cloud-based access-control platform used by gyms, coworking spaces, and clubs to manage doors,
readers, and who can open what. If your facility runs Kisi, you're in the right place — OpenCourt is building
an integration.
**This integration isn't live yet.** This page exists so you can find it and register interest. Nothing
below is available in your admin panel today.
How it would work [#how-it-would-work]
Kisi doesn't use typed keypad PINs the way most smart locks do. Instead it issues **access links** — and that
turns out to suit bookings well.
For each booking, OpenCourt would ask Kisi for an access link scoped to your doors, valid only for that
booking's window. Kisi returns a **QR code** and a web link, and the access **expires on its own** when the
window closes. Same idea as a door code: issued automatically, scoped to the right door, nothing to revoke.
Your customer would see the **QR code inside the OpenCourt app**, on the booking — right where a door code
appears today — and scan it at the reader on arrival. No Kisi app to download, no separate login.
Scanning needs a **Kisi Terminal Pro** (or another Kisi QR code scanner). A Kisi Reader Pro on its own
reads cards and mobile credentials but not QR codes, so check what's on your doors before planning around
this.
We're also looking at unlocking straight from the app, the way our other providers work, so a customer could
tap **Unlock** instead of scanning. Which of these ships first depends on what we hear from clubs actually
running Kisi.
Who this is for [#who-this-is-for]
Clubs that already run Kisi and don't want to replace it. If you're choosing an access-control system now and
door access through OpenCourt is important to you, one of our
[current integrations](/help/facility-operators/access-controls/choose-a-lock-for-your-club) will serve you sooner.
In the meantime [#in-the-meantime]
Kisi keeps working exactly as it does now — this integration would connect it to OpenCourt, not replace it.
Until then, you can still use OpenCourt's [manual access codes](/help/facility-operators/access-controls/door-codes-day-to-day) to show a door
code on bookings without any lock integration at all.
Register your interest [#register-your-interest]
Tell us you're on Kisi and we'll factor your setup into the build, then let you know when it's ready.
* Email [support@getopencourt.com](mailto:support@getopencourt.com), or
* Talk to your OpenCourt account representative.
Useful things to mention: how many doors, which Kisi readers you use, and whether you need access tied to
individual bookings or just general member access.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
* [Door codes day-to-day](/help/facility-operators/access-controls/door-codes-day-to-day)
# Salto KS mobile access
If your club runs a **Salto KS** access-control system, OpenCourt can connect to it so customers get
**phone-based (mobile key) access** instead of typing a keypad code. Their phone becomes the key: they hold it
near the lock and the door opens.
The initial connection is set up by the OpenCourt team. Once it's in place, **you assign and revoke keys
yourself**, customer by customer — that's the part you'll do day to day, and it's covered below.
You need access-control permission to assign keys. Customer profiles live under **Customers** in the admin
panel.
Getting Salto KS connected [#getting-salto-ks-connected]
Linking your Salto KS system to OpenCourt is a one-time setup we handle for you. It involves matching your
Salto **site**, **credential manager**, and **access group** to your club, and we do it this way because
getting those three wrong sends keys to the wrong doors.
To get started, [contact OpenCourt support](mailto:support@getopencourt.com) with:
* **Confirmation that your Salto KS account is linked to Seam.** OpenCourt reaches Salto through Seam, so this
has to exist first — your Salto administrator or installer can set it up.
* **Which Salto site** this club corresponds to, if your Salto account covers more than one location.
* **Which access group** customers should be placed in. This is the group that governs which doors they can
open and when, so pick the one you'd put a regular member in.
If you're not sure about the last two, loop in whoever administers your Salto KS account — they'll know.
We'll confirm once it's live, and from that point everything below is yours to run.
Grant mobile keys per customer [#grant-mobile-keys-per-customer]
Mobile keys are assigned **per customer**, not automatically to everyone. Open the customer's admin profile and
go to the **Access Controls** tab. The **Digital Keys Access** card — "Manage whether this user can receive Seam
mobile key credentials for this club." — shows their status as **Assigned** or not, and gives you **Assign** or
**Revoke**.
The card states the prerequisite plainly: "To assign digital keys, the user must have a complete profile:
first name, last name, and a valid email address." If **Assign** doesn't work, that's almost always why —
fix the profile on the **Details** tab first.
Mobile keys are presented in your club's **branded mobile app**, so customers need a recent version installed.
Do you still want door codes? [#do-you-still-want-door-codes]
Mobile keys and per-booking door codes are **independent**. You can run either or both:
* **Mobile keys only.** The access-code mode stays **Off**. Nobody gets a PIN; access is entirely phone-based
through the keys you assign. This is the common shape for clubs on Salto KS.
* **Both.** The mode is set to **Smart Lock**, so bookings also generate keypad codes, and mobile keys go to
the people you assign them to — members and staff, typically, with drop-ins falling back to a code.
Tell us which you want when we set the connection up, and mention it any time you want to change. It matters
more than it sounds: with codes **Off**, a customer without an assigned mobile key has **no way in**.
What the customer sees [#what-the-customer-sees]
On a mobile-key setup, the customer taps **Door access** on your club's home screen and a **Club access**
screen opens **inside your club's own branded app** — a native screen, not a separate Salto app and nothing
extra to download. Their phone *is* the key, so they hold it near the lock instead of typing a code.
**Tell your front desk this one thing:** the screen says *"Hold your phone close to the lock. It may take 5–10
seconds to open,"* and while it works it shows *Looking for the lock…* and sometimes *Retrying unlock…* That
searching phase is normal Bluetooth behavior, not a failure. Customers who walk away after two seconds will
report the door as broken when nothing is wrong.
This is the one part of OpenCourt door access that requires your **branded mobile app**. Customers on the web
app won't see it. See
[Getting through the door at your club](/help/players/access-controls/unlock-a-door-from-the-app).
Access stays centralized in your Salto KS platform: OpenCourt grants and revokes membership in the access
group you nominated, rather than running a parallel system. Which doors that group opens is defined in Salto,
so it's Salto — not OpenCourt — that decides where a key works.
If something goes wrong [#if-something-goes-wrong]
* **A customer doesn't get a mobile key** — check their **Access Controls** tab shows **Assigned**, and that
their profile has a first name, last name, and valid email. Then confirm they're on a current version of
your club's app.
* **The key screen sits on "Looking for the lock…"** — that's Bluetooth searching, and it can take 5–10
seconds. Have them hold the phone within a few inches of the reader with Bluetooth on, and wait. If it never
connects, check the lock has power and is online in Salto.
* **A customer can't find Door access in the app** — mobile keys only appear in your club's **branded mobile
app**. On the web app there's nothing to show. Confirm they've installed the app and are signed in.
* **You need to change which doors customers can open** — that's governed by the Salto **access group** we
mapped, so it's changed in Salto KS, not in OpenCourt. Adjust the group's permissions in your Salto console,
or [contact us](mailto:support@getopencourt.com) if you want customers moved to a different group.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Connect a Seam lock to your club](/help/facility-operators/access-controls/connect-a-seam-lock)
* [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app)
# Set who can unlock doors from the app
Decide whether customers can open a door straight from the OpenCourt app, and set per-lock rules for **who** can
unlock and **when**. *(About 5 minutes. You'll need admin access and a lock that supports remote unlock.)*
You need access-control permission. Everything here lives under **Settings → Access Controls**. Per-lock
**Door access** rules are available on **Seam**, **Rhombus**, and **UniFi Access** locks that support remote
unlock. RemoteLock manages its own codes, so a RemoteLock lock shows only the **door code window** settings —
not the who-can-unlock rules. **Customers can still unlock a RemoteLock door from the app** once you turn on
in-app unlocking below — it just uses the standard reservation window (30 minutes before until 10 minutes
after) for everyone, with no per-role overrides.
In-app unlocking is separate from door codes: a customer might get in with a **door code**, with **in-app
unlock**, or both. This page covers in-app unlock — but a lock's **default** rule also sets the **door code
window** (when a booking's code activates and expires), so that one timing applies to both. Overrides don't;
see the callout under "Per-lock access rules" below.
There are two layers of control.
1. The club-wide switch [#1-the-club-wide-switch]
Go to **Settings → Access Controls** and find the **Remote Unlock** section — "Allow users to unlock doors from
the club home page. Access rules on each lock control who can unlock and when." Switch it to **Enabled**. While
it's **Disabled**, customers never see an unlock option — they use their door code instead.
The Remote Unlock section only appears once you're in Smart Lock mode with at least one connected lock that
supports remote unlock.
2. Per-lock access rules (who, and when) [#2-per-lock-access-rules-who-and-when]
Open a lock from the **Locks** tab and find its **Door access** section — "Control who can unlock this lock
from the app and when — and, for locks with door codes, when a booking's code is active."
Start with the **Default access rule**. It offers three modes:
| Mode | What the customer can do |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Can always unlock** | Unlock whenever, regardless of bookings. |
| **During reservations only** | Unlock only around their booking — set **min before** and **min after** (default: **30 min** before to **10 min** after). |
| **No app unlock** | No in-app unlock for this rule set. |
Below that, **Overrides (optional)** lists your rule sets — **Non-members** plus each rule set you've created
(for example *Coach* or *Legacy Member*). Each row shows **Using default** until you switch it on, at which
point it reads **Custom rule** and opens the same three modes. So you might leave the default at *During
reservations only* and give coaches *Can always unlock*.
**The default rule and an override do different things to door codes.**
* On the **Default access rule**, the min before / min after window sets *both* the app-unlock window and
when a booking's **door code** goes active. The page says so: "These minutes also set when a booking's door
code is active."
* On an **override**, the minutes move *only* the app unlock button: "Applies to the app unlock button only —
door codes always use the default window above."
So if you want a group's **door code** to activate earlier, change the **default** window. Widening an
override won't do it.
When you switch an override to **Custom rule** it starts out matching the default — same mode, same minutes.
That's a starting point, not a link: change it and it stays changed, and later edits to the default won't
flow through.
If the effective rule for non-members works out to **Can always unlock**, the page raises an amber alert:
**"Non-members can unlock this door anytime."** — *"With this rule, anyone signed in to OpenCourt who isn't a
member of your club can unlock this door at any time — no booking required. If you only meant members, set
the Non-members override below to 'During reservations only' or 'No app unlock'."* Only leave it that way on
purpose.
The separate "Door code window" field [#the-separate-door-code-window-field]
If you set the default rule to **Can always unlock** or **No app unlock**, the min before / min after fields
disappear — but a code-capable lock still needs to know when a booking's code is live. So a separate **Door
code window** box appears, captioned "When a booking's keypad code is active, relative to the reservation."
Set it there instead.
**Code-only locks show just this box.** A keypad with no remote unlock, or a RemoteLock lock that pushes its
own codes, has no app-unlock policy to configure — the whole **Door access** section collapses to the **Door
code window** field.
Steps [#steps]
1. In **Settings → Access Controls**, set **Remote Unlock** to **Enabled**.
2. Open the lock you want to configure and go to its **Door access** section.
3. Set the **Default** rule's mode. For *During reservations only*, set the **min before** and **min after**.
4. (Optional) Switch **Non-members** or a specific rule set to **Custom rule** and set its mode.
5. Save.
What customers see [#what-customers-see]
Two things, and they're independent:
* **An unlock control on their reservation card**, which counts down (*"Unlock available in 12 min"*), turns
into a green **Unlock door** button when your window opens, and reads *"Door offline — try again shortly"*
if the lock is unreachable.
* **A Door access button** on the club home screen. Tapping it lists the doors they can unlock — or, for
mobile-key setups, opens the door-access screen in your club's branded app.
Because they're independent, a customer can have a perfectly good door code while the unlock button shows the
door offline. The code is stored on the lock, so it still works. See
[Getting through the door at your club](/help/players/access-controls/unlock-a-door-from-the-app).
If something goes wrong [#if-something-goes-wrong]
* **Customers don't see an unlock option** — check that **Remote Unlock** is **Enabled**, the customer's rule
set isn't on **No app unlock**, and (for *During reservations only*) they're inside the allowed window with a
booking on the space mapped to that door.
* **There's no Door access rules section on a lock** — who-can-unlock rules appear on **Seam**, **Rhombus**,
and **UniFi Access** locks that support remote unlock. A RemoteLock lock shows only the door code window; its
customers can still unlock from the app, on the standard reservation window.
* **A non-member can unlock when they shouldn't** — set the **Non-members** override to **No app unlock**, or
to *During reservations only*.
* **A customer still can't get in** — work through
[A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in).
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Getting through the door at your club](/help/players/access-controls/unlock-a-door-from-the-app)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [A customer can't get in — troubleshoot door access](/help/facility-operators/access-controls/troubleshoot-customer-cant-get-in)
* [Set up Salto KS mobile access](/help/facility-operators/access-controls/salto-ks-mobile-access)
# Thermostat control (coming soon)
{/*
COMING-SOON placeholder published for SEO/AI-search reach (2026-08-02, Alex's call).
Nothing is built — no thermostat code anywhere in the repo (verified 2026-08-02).
Reachable via Seam alongside the locks we use today. Brand list re-verified against
seam.co/supported-devices-and-systems on 2026-08-02 (ecobee, Nest, Honeywell, Sensi, Tado, Venstar,
Trane, American Standard, Aprilaire, Sinope, LUX, + Sensibo for ductless mini-splits / IR AC).
Seam's thermostat API does heat/cool/auto/eco/off, fan modes, named climate presets, daily+weekly
programs, and /thermostats/set_temperature_threshold which emits
thermostat.temperature_threshold_exceeded -- that's the basis for the HVAC-failure alerting section.
Positioning per Alex 2026-08-02: 24/7 UNSTAFFED venues are the primary case, and cooling is
first-class, not an afterthought. Keep claims capability-neutral until scoped; nothing is built.
*/}
Conditioning an empty building is one of the larger costs a club carries, and one of the easiest to get
wrong — a space that's freezing when the first booking starts, a bay that's stifling by mid-afternoon, or
HVAC running all night for nobody. OpenCourt is building **smart thermostat control** so temperature follows
your bookings instead of a fixed schedule.
**This isn't live yet.** This page exists so you can find it and register interest. There's no thermostat
setting in your admin panel today.
Built for unstaffed hours [#built-for-unstaffed-hours]
This matters most at venues that run **24/7 with nobody on site** — indoor golf, self-serve courts, late-night
and early-morning slots. When there's no one to flip a switch, the building either runs all night or the first
customer of the day walks into an uncomfortable space. Neither is good, and one of them is expensive.
Because bookings already drive door access, they can drive temperature the same way, with no one present and
nothing for staff to remember.
Heating and cooling, equally [#heating-and-cooling-equally]
Cooling is the half people forget. An indoor golf bay with a projector, a screen and four people in it heats
up fast, and hot-climate clubs spend more on air conditioning than northern clubs spend on heat. This works the
same in both directions:
* **Pre-condition before arrival** — warm or cool, whichever the space needs, so the first booking of the day
starts comfortable.
* **Fall back when nothing's booked**, including gaps between bookings and the long unbooked stretch overnight.
* **Follow the space, not the building** — a club with several bays, courts, or studios rarely needs all of
them conditioned at once.
Catching HVAC problems overnight [#catching-hvac-problems-overnight]
The same connection reads the actual temperature back, so a space that drifts far outside its expected range
can raise an alert. At an unstaffed venue that's the difference between finding out at 6am and finding out
when a customer arrives at 6am.
The hardware [#the-hardware]
The same platform we already use for smart locks, **Seam**, also connects thermostats from **ecobee**,
**Google Nest**, **Honeywell**, **Sensi**, **Tado**, **Venstar**, **Trane**, **American Standard**, **Aprilaire**
and **Sinopé**. So for many clubs this would run on hardware you may already own, through a connection you may
already have.
If your space is cooled by **ductless mini-splits or a wall AC unit** rather than central HVAC — common in
converted units and smaller studios — **Sensibo** is on the same list and controls those, so you're not shut
out by not having a conventional thermostat.
Brand support changes, so check a specific model on
[Seam's supported devices list](https://www.seam.co/supported-devices-and-systems).
Who this is for [#who-this-is-for]
Any club paying to condition space that isn't always occupied, and **especially venues running unstaffed
around the clock**. The savings scale with how much of your day is unbooked — which, for a 24/7 space, is most
of it.
In the meantime [#in-the-meantime]
Nothing to do. If you're replacing a thermostat or adding AC control soon, choosing something from the list
above keeps this option open without committing you to anything.
Register your interest [#register-your-interest]
We're prioritising this partly by who tells us they want it, so it's worth a message.
* Email [support@getopencourt.com](mailto:support@getopencourt.com), or
* Talk to your OpenCourt account representative.
Useful things to mention: which thermostats or AC controllers you run (brand and model), how many zones,
whether you operate unstaffed overnight, and whether you want temperature to follow individual bookings or
just your opening hours.
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Which locks work with OpenCourt](/help/facility-operators/access-controls/choose-a-lock-for-your-club)
# A customer can't get in — troubleshoot door access
"A customer can't get in" has two very different causes, and they're fixed in opposite ways. Either the **lock is down** — a connection hiccup that fails for *everyone* and is fixed on site — or **this one customer's access** isn't valid right now, which is fixed in your settings or by explaining the timing. The customer only ever sees "it didn't open," so your first job is to tell the two apart.
Everything here lives under **Settings → Access Controls** and the **Access control** pages in your admin panel. You'll need access-control permission.
First: is it everyone, or just this customer? [#first-is-it-everyone-or-just-this-customer]
Don't try to ask the customer "does it work for everyone else?" — they don't know. Figure out the scope yourself:
1. **Have staff (or a known-good account with a current booking on that door) try the same door.** If it also fails, the lock is down for everyone. If it works, the problem is specific to this customer.
2. **Check the unlock history.** Open the **Unlock history** tab and look at the last hour. A run of **Unlocked** rows from *other* people means the lock is fine and this is a per-customer issue. **Access Denied**, **Unlock Failed**, or **Device Disconnected** rows across *multiple different* people means the lock is down.
The **Method** column is what makes this readable. **Keycode** rows are people typing a booking code, and their
**Details** links to the event — those are the ones you can trace. **Manual** rows are the door being opened by
hand from the inside, with no code involved. Don't mistake a healthy run of Manual unlocks for a problem. Full
breakdown in [Door codes day-to-day](/help/facility-operators/access-controls/door-codes-day-to-day#reading-the-method-column).
* **Fails for everyone →** jump to [The lock is down for everyone](#the-lock-is-down-for-everyone).
* **Works for others →** jump to [One customer can't get in (others can)](#one-customer-cant-get-in-others-can).
The lock is down for everyone [#the-lock-is-down-for-everyone]
When unlock fails for everyone, it's almost always a temporary connection hiccup between the lock (or its controller) and its provider — not anyone's account. It usually clears within a few minutes.
* **Symptoms:** unlock worked recently, then started failing for multiple different people; the app shows "unlock failed" or just spins; the unlock history shows **Device Disconnected**, **Unlock Failed**, or **Low Battery** rows.
* **Wait 1–2 minutes and retry.** These hiccups often self-clear.
* **Power-cycle the controller on site.** Find the access-control unit wired to the door, unplug it, wait about 15 seconds, plug it back in, give it a minute to come back online, then try again. This resolves the large majority of cases.
* **Test from the admin side.** Open the lock's page and use the **Unlock** button in the header. The status bar there shows whether the lock is online and its battery level — a **Low Battery** warning is worth acting on before it fails completely.
Scroll down the same page for **Lock Activity**, which narrows to that one lock and adds a **From** / **To**
date range. Alongside the Locked/Unlocked events you'll see OpenCourt's own code operations — *Access Code
Scheduled*, *Access Code Removed*, *Access Code Deleted*, *Access Code Time Frame Changed* — each with the code
and its booking. That's the record that answers "did their code ever actually reach this lock?"
If the controller is powered and online but unlock still fails for everyone, or a power-cycle didn't help (or it keeps recurring), contact OpenCourt support with the door, when it started, and what the unlock history shows.
One customer can't get in (others can) [#one-customer-cant-get-in-others-can]
The lock is fine — others are getting in. Now it's about *how* this customer gets in and *when* they're trying. Work through the symptom that matches.
Their door code doesn't work [#their-door-code-doesnt-work]
Codes are time-limited. The same rule that governs in-app unlock drives the code window: by default a code activates **30 minutes before** the reservation and expires **10 minutes after** it ends (a per-lock rule can change this). Outside that window the code does nothing.
1. Open the **Access codes** tab and find their code.
2. Check the **Valid From**, **Valid Until**, and **Status** columns. **Upcoming** means it hasn't turned on yet (they're early). **Expired** or **Revoked** means the window has passed or the booking was cancelled. Only **Active** codes open the door.
3. Confirm the **space** column on the code matches the space they actually booked — a code only opens the door mapped to that space. (That column is headed **Court**, **Bay**, or **Field**, matching your club.)
A big gap between **Created At** and **Valid From** is normal. A code for a booking weeks out is created the
moment the booking is made, sits **Upcoming**, and only becomes **Active** in its window.
A code that isn't loaded onto the lock yet is normal, not broken. Native scheduling pushes codes about **72 hours** ahead; Just-in-Time pushes them about **60 minutes** before (the lock must be online then). On RemoteLock, a code stays **pending** until the lock confirms it, so a pending code ahead of the booking is expected.
They don't see an unlock option in the app [#they-dont-see-an-unlock-option-in-the-app]
In-app unlock needs a chain of things to all be true. Check them in order:
1. **Club-wide unlock is on.** In **Settings → Access Controls**, the **Remote Unlock** setting must be enabled ("Allow users to unlock doors from the club home page…"). If it's off, no one sees the option.
2. **The lock supports remote unlock.** Some locks only issue codes and can't be unlocked remotely.
3. **Their rule set allows it.** The per-lock **Access Rule** for their rule set must not be *No app unlock*.
4. **They're in the window, on the right space.** If the rule is *During reservations only*, they must be inside the window (default 30 min before to 10 min after, per-lock adjustable) and their booking must be on the court mapped to that door.
The app says access denied / not authorized [#the-app-says-access-denied--not-authorized]
This means they reached the lock but the rule turned them away. Two usual causes:
* **Their rule set's Access Rule is "No app unlock"** — that role is intentionally not allowed to unlock this door. Check the door's rules on the lock page and confirm the rule assigned to their rule set (including any **Non-members** override).
* **They're outside the "During reservations only" window**, or their booking is on a space that isn't mapped to this door. Confirm the timing and the court.
Their code changed [#their-code-changed]
If you (or the customer) moved the booking to a **different space or door**, OpenCourt issues a **new** code for the new door and sends a "Your access code changed" email. The old code stops working. Ask them to use the latest code from the app (booking details → **Access code**) or their most recent confirmation email. A plain reschedule that keeps the same court keeps the same PIN with an updated window.
Membership changed and access stopped [#membership-changed-and-access-stopped]
Access rules can differ by rule set. If a customer's membership lapsed or changed, they may fall under a different rule set — often the **Non-members** override — whose Access Rule is *No app unlock* or a narrower window. Check which rule set they're on now and what that rule set's Access Rule allows.
Every **in-app** unlock attempt — success or failure — is recorded in the club activity log with the customer's name, since they were signed in when they tapped. If the customer's memory of "it just stopped" doesn't match, the activity log shows exactly what happened and when. (Keypad entries land in Unlock History instead, tied to the code and its booking rather than a person.)
Still stuck? [#still-stuck]
If the customer clearly should get in — valid **Active** code (or all four unlock conditions met), right space, right time — and still can't, contact OpenCourt support. Include:
* The **customer's name**
* The **door** (lock name)
* The **time it failed**
* What the **unlock history** shows for that attempt
Related [#related]
* [How access controls work in OpenCourt](/help/facility-operators/access-controls)
* [Set who can unlock doors from the app](/help/facility-operators/access-controls/set-who-can-unlock-doors)
* [Access codes & scheduling](/help/facility-operators/access-controls/access-codes-and-scheduling)
* [Door codes day to day](/help/facility-operators/access-controls/door-codes-day-to-day)
* [Unlock a door from the app](/help/players/access-controls/unlock-a-door-from-the-app)
# How BayControl works for simulator bays
BayControl locks each golf simulator bay whenever nobody has booked it, and opens it for the customer who did.
Customers type the code from their booking on the bay's screen and play; when their time is up, the bay locks
itself again. The result is **unstaffed bays** — you can sell late-night and early-morning slots without anyone at
the desk.
BayControl is part of OpenCourt and follows your OpenCourt booking schedule. It is being switched on club by
club — [contact us](/contact) to add it to your venue.
What does BayControl do for my venue? [#what-does-baycontrol-do-for-my-venue]
* **Locks a bay when it is free.** Every screen in the bay shows your club's lock screen — your name, a clock,
the next booking, and a QR code that lets a walk-up customer book the bay on their phone.
* **Opens for the paying customer.** Every booking on a bay comes with its own code. The bay greets the customer
and asks for it.
* **Stays out of the way during play.** Once the bay opens, the game has the screens. The only thing on top is a
small end-of-session notice in the corner you choose.
* **Ends sessions on time.** Customers get warnings before their time runs out — 10, 5 and 1 minutes by default —
and the bay locks itself, ready for the next booking.
* **Keeps working when the internet does not.** A network drop does not lock a paying customer out of a bay they
paid for, and your staff can still open a bay.
* **Puts every bay on one screen.** The admin panel shows which bays are locked, in session, or need attention,
and lets staff open or lock a bay from the front desk or a phone.
Does BayControl work with my simulator? [#does-baycontrol-work-with-my-simulator]
Yes. BayControl works with all the top golf simulators, and it needs no new hardware. Your bays keep running the
simulator software they run today.
Running something less common? Tell us which simulator software your bays use and we'll confirm it before you
start.
What do my customers see? [#what-do-my-customers-see]
1. They book a bay in OpenCourt, the same way they do now.
2. Their code arrives with the booking — on the booking in the OpenCourt app, labelled **Bay unlock code**, and in
their confirmation and reminder emails. Nobody at the desk has to hand anything out.
3. At the bay, the screen greets them by name and asks for the code. A few minutes before the start time is
fine.
4. They play. Near the end, a small notice counts down their remaining time.
5. When their time is up, the bay thanks them and locks for the next booking.
The customer's side is in [Unlock your simulator bay](/help/players/simulator-bays/unlock-your-simulator-bay).
How do staff handle walk-ins and problems? [#how-do-staff-handle-walk-ins-and-problems]
* **A walk-in or a lesson with no booking:** staff open the bay for a set number of minutes from the admin panel,
and it locks itself again when the time runs out. Staff can also open a bay at the bay itself.
* **A customer who cannot find their code:** staff read it back to them from the booking in the admin panel.
* **A session that has to end now:** staff lock the bay from the admin panel.
What do I need to use BayControl? [#what-do-i-need-to-use-baycontrol]
* **Your simulator bays booked through OpenCourt.** BayControl follows your OpenCourt schedule.
* **The PC that already runs each bay's screens and simulator.** There is nothing new to buy.
* **An internet connection** at the venue.
* **BayControl switched on for your club.** [Contact us](/contact) and we'll set it up with you.
Common questions [#common-questions]
Do I need a smart lock or new hardware? [#do-i-need-a-smart-lock-or-new-hardware]
No. BayControl locks the bay's screens and simulator, not a door, and it uses the PC each bay already has. If your
club also uses OpenCourt's [door locks and access controls](/help/facility-operators/access-controls), the two work
side by side: a customer gets an **Access code** for the door and a **Bay unlock code** for the bay.
What happens if the venue's internet goes down? [#what-happens-if-the-venues-internet-goes-down]
Customers with a booking still get in, and your staff can still open a bay. New bookings made during the outage
reach the bay once the internet is back.
Can customers start early or get extra time at the end? [#can-customers-start-early-or-get-extra-time-at-the-end]
Yes. By default a code works from 5 minutes before the booking until 2 minutes after it, and a customer can take
one free extra minute at the end to save their round. You set all of these for your club in the admin panel.
Can I match the lock screen to my brand? [#can-i-match-the-lock-screen-to-my-brand]
Yes. The lock screen shows your club's name, and you choose its colors in the admin panel.
Can I try it before rolling it out to every bay? [#can-i-try-it-before-rolling-it-out-to-every-bay]
Yes. Start with one bay, check it with your team, then add the rest. [Contact us](/contact) to plan it.
Guides for BayControl clubs [#guides-for-baycontrol-clubs]
Clubs using BayControl have step-by-step guides for setup and day-to-day running.
[Open the club guides](/help/facility-operators/bay-control/set-up-bay-control) with the help password OpenCourt
gave your club.
# Auto-Allocating with Memberships
How It Works [#how-it-works]
There are three pieces to the system:
1. Booking Pass - Define the benefit [#1-booking-pass---define-the-benefit]
[A booking pass](/help/facility-operators/booking-and-guest-passes/what-are-booking-passes) defines what the benefit is. You create it once, and it gets allocated to members repeatedly.
Types of the most popular booking passes:
1. [**Guest pass (e.g. members get 3 guest passes per month)**](/help/facility-operators/booking-and-guest-passes/creating-a-guest-pass)
2. [**Free reservation pass (e.g. members get 4 free reservations a month)**](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass)
3. [**Free court hours pass (e.g. members get 5 free hours for court bookings per month)**](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass)
4. [**Free event pass (e.g. members get 1 free Open Play a week or 1 Clinic a week)**](/help/facility-operators/booking-and-guest-passes/create-a-free-event-pass)
5. [**Free event with specific event tag pass (e.g. members get 1 free specific group class per week)**](/help/facility-operators/booking-and-guest-passes/creating-a-free-pass-for-events-with-a-specific-tag)
6. [**Free lesson pass (e.g. members get 1 free 1hr private lesson per month)**](/help/facility-operators/booking-and-guest-passes/creating-a-free-lesson-pass)
Each one of those can be a family shared pass.
***
2. Allocation Rules - Define who gets it and when [#2-allocation-rules---define-who-gets-it-and-when]
An allocation rule connects pass templates to memberships. It says: "Members with \[this membership] get \[these passes] every \[week/month/etc.]."
[You can find more information on how to do it here.](/help/facility-operators/booking-and-guest-passes/creating-an-allocation-rule)
***
3. Pass Allocations - The actual passes members receive [#3-pass-allocations---the-actual-passes-members-receive]
When the rule fires, individual pass instances are created for each eligible member. These are the actual passes that get consumed during booking.
***
What Happens Automatically [#what-happens-automatically]
Once a rule is set up, the system handles everything:
When a member's membership activates [#when-a-members-membership-activates]
Passes are created immediately for the current period (and any pre-created future periods). The member can start using them right away.
At the start of each new period [#at-the-start-of-each-new-period]
A scheduled job runs daily at 5 AM (club's local time). For each rule, it checks which periods are due, finds all eligible members, and creates fresh passes. Members wake up to new passes in their account.
When a member changes their membership [#when-a-member-changes-their-membership]
The system automatically adjusts:
* **Upgrade** (e.g., Basic → Premium) — Old passes stay active until they expire. New passes from the Premium rule are created.
* **Downgrade** (e.g., Premium → Basic) — Premium passes that haven't started yet are archived. Basic passes are created.
* **Same product, different price** — If the rule has price-level filters, eligibility is recalculated.
Before confirming a membership change, admins see an **impact preview** showing exactly which passes will be archived (red) and which will be created (green).
When a member cancels their membership [#when-a-member-cancels-their-membership]
* Passes that are currently active stay usable until the membership end date
* Pre-created future passes (for periods after membership end) are archived immediately
* Passes that overlap the cancellation boundary are marked "Pending Archival" — usable now but will be archived when the membership expires
When a member's membership is terminated immediately [#when-a-members-membership-is-terminated-immediately]
All passes are archived immediately. Past bookings made with those passes remain valid — nothing is retroactively revoked.
When a membership is frozen [#when-a-membership-is-frozen]
Passes become unusable during the freeze but aren't deleted. When the membership resumes, all passes (including ones created during the freeze) become usable again.
***
How Members Use Their Passes [#how-members-use-their-passes]
Viewing Passes [#viewing-passes]
Members can see their passes at **My Profile → Booking Passes**, organized by status:
* **Active** — Currently usable, with remaining uses/minutes and expiration date
* **Upcoming** — Start date is in the future (pre-created passes)
* **Expired** — Validity period ended
* **Exhausted** — All uses or minutes consumed
Using Passes During Booking [#using-passes-during-booking]
When a member books an event or reserves a court:
1. The system checks all their active passes against the booking:
* Does the pass support this event type?
* Does the pass match the event's tags? (if tag-restricted)
* Is the event within the pass's time restrictions?
* Does the pass have remaining uses or minutes?
2. Matching passes are shown during checkout
3. The member selects which pass to apply
4. The pass is consumed — remaining uses or minutes are decremented
5. If the booking is refunded later, the pass is restored
***
Managing Rules (Admin) [#managing-rules-admin]
Editing a Rule [#editing-a-rule]
When you edit an existing rule (change the schedule, product filters, or pass configurations), the system shows a confirmation dialog:
* **Passes being removed** (red) — Templates or configurations that are being removed. Pre-created future passes from these will be archived.
* **Passes being added** (green) — New templates or configurations. Passes will be created for eligible members.
* **Passes unchanged** (gray) — No change to these.
Archiving a Rule [#archiving-a-rule]
Archiving a rule stops future allocations. Existing passes that were already created remain active and usable — they're not retroactively removed.
Activity Log [#activity-log]
Each rule has an **Activity** tab showing every allocation run:
* When it ran (scheduled time and actual execution time)
* How many users were processed
* How many passes were created
* Execution duration
* Status (Completed, Failed, In Progress)
* For failed runs: error details and a retry button
Manually Granting Passes [#manually-granting-passes]
Besides auto-assignment, admins can manually grant passes to specific users from **Booking Passes → Grant**. This is useful for one-off situations like comp passes, promotional offers, or correcting missed allocations.
***
Example Setup [#example-setup]
Here's how a club might set up passes for three membership tiers:
**Gold Membership ($150/month)**
* Rule: Monthly, 1st of each month, pre-create 7 days ahead
* Passes: 12 Open Play Sessions + Unlimited Court Bookings + 50% Off Clinics
**Silver Membership ($100/month)**
* Rule: Monthly, 1st of each month, pre-create 7 days ahead
* Passes: 8 Open Play Sessions + 4 Hours of Court Time
**Basic Membership ($50/month)**
* Rule: Monthly, 1st of each month, pre-create 7 days ahead
* Passes: 4 Open Play Sessions
Each month:
1. On the 25th (7 days before the 1st), next month's passes are pre-created and visible as "Upcoming"
2. On the 1st, passes become active
3. Members book events throughout the month, consuming passes
4. At the end of the month, unused passes expire (if configured with a 1-month validity)
5. Cycle repeats
***
Tips [#tips]
* **Start with "Whole Event" passes** for simple session-based benefits — they're the easiest to understand and manage
* **Use "By Minutes" passes** when booking durations vary (e.g., members can book 30-min, 60-min, or 90-min slots from the same pool)
* **Pre-create passes 7 days ahead** so members can see their upcoming passes before the new period starts
* **Use tag restrictions** to differentiate benefits (e.g., "Beginner Clinic Pass" only works for events tagged "Beginner")
* **Check the Activity tab** after setting up a new rule to confirm passes were allocated correctly
* **Use the impact preview** before changing memberships — it shows exactly what will happen to the member's passes
* **Don't delete pass templates** if they're referenced by active rules — archive them instead
# Create a Family-Shared Pass
**Example:** A family membership includes 10 hours of court time per month, shared between all family members.
***
How Family Sharing Works [#how-family-sharing-works]
* The primary member (pass holder) gets the pass allocated via a membership
* All linked family members automatically become pass holders too
* Everyone draws from the **same pool** — if the pass has 10 hours, the entire family shares those 10 hours
* Family sharing applies to all existing and future allocations of that pass template
Family members are managed through the [**Family** section of a member's profile](/help/facility-operators/customers-and-families/creating-and-managing-a-family-account). Each family member must be linked to the primary member.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes → Booking Passes** (Manage tab)
2. Click **Create Booking Pass**
Fill in the form:
| Field | Value |
| ------------------- | ---------------------------------------------------- |
| **Name** | Family Court Hours |
| **Display Name** | Family Court Time *(optional)* |
| **Pass Applies To** | Event |
| **Redemption Mode** | By Hours *(or Whole Event, depending on your needs)* |
| **User Type** | Pass Holder Only |
Toggle on **"Can be redeemed by family members"**.
Under **Event Restrictions**, check the event types the pass should cover — e.g., **Reservations**.
Click **Create Booking Pass**.
***
How It Works for Members [#how-it-works-for-members]
1. A parent (primary member) has a Family Membership with 3 linked family members
2. On the 1st of the month, 600 minutes (10 hours) are allocated to the parent
3. All family members can see and use the pass in their own accounts
4. The parent books a 90-minute court → 510 minutes remaining
5. A family member books a 60-minute court → 450 minutes remaining
6. Everyone draws from the same pool until it's used up
7. On the 1st of next month, a fresh 600-minute pool is allocated
Every family member sees the same remaining balance under **Booking passes** in their profile, so the pool is always in sync.
***
Family Sharing with Different Pass Types [#family-sharing-with-different-pass-types]
Family sharing works with any pass type and redemption mode:
| | Pass TypeHow sharing works |
| ------------------------------------------------- | ------------------------------------------------------------------------ |
| **Whole Event** (e.g., 4 free reservations) | Each family member's booking consumes one pass from the shared pool of 4 |
| **By Hours** (e.g., 10 hours of court time) | Each family member's booking deducts from the shared hour pool |
| **Percentage Discount** (e.g., 20% off) | Each family member gets the discount applied when they book |
| **Fixed Discount** (e.g., $10 off) | Each family member gets the discount applied when they book |
| **Coach / Whole Lesson** (e.g., 2 lesson credits) | Each family member can book lessons using the shared credits |
***
Variations [#variations]
**Per-member passes (no sharing):** If you want each family member to get their own separate pass, leave family sharing OFF and create individual allocation rules per membership. Each person gets their own pool.
**Guest pass + family sharing:** You can enable both family sharing and Guest Only user type — but this is unusual. More commonly, you'd create a family-shared "Pass Holder Only" pass for the family's own bookings and a separate "Guest Only" pass for bringing non-family guests.
***
Key Points [#key-points]
* **Family members share one pool** — they don't each get their own allocation. If you allocate 4 passes, that's 4 total for the entire family, not 4 per person.
* Family sharing is set on the **pass template**, not the allocation rule. Once enabled, it applies to every allocation of that template.
* **Adding a new family member** to the primary account gives them immediate access to any family-shared passes the primary member has.
* **Removing a family member** revokes their access to the shared passes.
* Family members are linked through the member's profile — the admin doesn't need to allocate passes to each family member separately.
# Create a Free Event Pass
**Example:** Members get 1 free Open Play session or 1 Free Clinic per week.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Event that it applies to.
5. Choose Whole Event/Reservation
6. Choose Pass Holder Only as a user type that it can be applied to.
7. If you want your members to share it with their family members, toggle on this setting:
8. Under **Event Restrictions**, check only **Open Play (or Clinic, or other Event type)**. Leave Reservations and other event types unchecked.
Click **Create Booking Pass**.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. Choose how many days in advance the passes should be issued (Lead Time). For example, if members can book 3 days in advance, the passes should be issued 3 days before the start of the new week or month. If passes are issued weekly, also select the day of the week when they should be allocated.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many passes you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A Gold member joins an Open Play event
2. The system finds an available free Open Play pass and applies it
3. The event fee is waived — the pass is consumed
4. If the member joins another Open Play that same week, they pay full price
5. Next Monday (or the chosen day), a new pass is allocated automatically
***
Variations [#variations]
**Multiple event types:** If you want the pass to cover both Open Play and Tournaments, check both under Event Restrictions. The pass will apply to either type.
**Monthly instead of weekly:** Change the allocation rule frequency to "Month(s)" and set the day of month. For example, 2 free Open Play sessions per month.
***
Key Points [#key-points]
* Each event entry consumes one pass, regardless of the event's duration
* The pass only covers the event types you selected — other event types are unaffected
* Unused passes expire at the end of the week (based on the 1-week validity) unless you check **"Never expires"**
* Members can see their remaining passes in **My Profile → Booking Passes**
# Creating a Free Court Hours Pass
**Example:** Premium members get 5 free hours for court bookings per month.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Event that it applies to.
5. Choose Whole Event/Reservation
6. Choose Pass Holder Only as a user type that it can be applied to.
7. If you want your members to share it with their family members, toggle on this setting:
8. Under **Event Restrictions**, check only **Reservations**. Leave all event types (Open Play, Clinic, etc.) unchecked — this pass should only apply to court reservations.
Click **Create Booking Pass**.
**Note:** "By Hours" is only available for Event passes — not Coach passes.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. How many days in advance you’ll issue them (Lead Time) - e.g. your members can book 7 days in advance, then they’ll need to have passes 7 days in advance before the new month/week starts.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many hours (minutes) you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A Premium member books a 90-minute court reservation
2. The system deducts 90 minutes from their pool (300 → 210 minutes remaining)
3. They book another 60-minute reservation — pool goes to 150 minutes
4. They can keep booking until the pool runs out
5. If they try to book a 2-hour slot with only 90 minutes left, the pass won't cover it — they pay full price
6. On the 1st of next month, a fresh 300-minute pool is allocated
Members can see their remaining balance in **My Profile → Booking Passes** (displayed as hours and minutes, e.g., "3h 30m remaining").
***
When to Use Hours vs Whole Event [#when-to-use-hours-vs-whole-event]
| | ScenarioUse |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Members get a fixed number of sessions (e.g., 4 bookings/month) | **Whole Event** — see [Free Reservation Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass) |
| Members get a time budget they can split freely (e.g., 5 hours/month) | **By Hours** — this guide |
The "By Hours" mode is more flexible — members can book three 90-minute sessions or five 60-minute sessions, whatever they prefer.
***
Key Points [#key-points]
* The hour pool is set in the **allocation rule** (Minutes Available field), not on the pass template
* A booking must fit entirely within the remaining pool — partial coverage is not supported
* Unused hours expire at the end of the month unless you check **"Never expires"** in the allocation rule
* The pass applies to all event types you selected in Event Restrictions — if you only checked Reservations, Open Play bookings won't deduct from the pool
# Creating a Free Lesson Pass
**Example:** Members get 1 free 1-hour private lesson per month.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Coach that it applies to.
5. Choose Whole Event/Reservation
6. Choose Pass Holder Only as a user type that it can be applied to.
7. If you want your members to share it with their family members, toggle on this setting:
8. Under **Coach Restrictions**, choose how specific you want to be.
Option A: Any coach, any service [#option-a-any-coach-any-service]
Select **"All coach lessons"**. The pass works for any coach at the club, for any of their services.
Option B: Specific coach, all their services [#option-b-specific-coach-all-their-services]
Select **"Specific coaches"** → check the coach. Leave their services unchecked — this means the pass covers all services that coach offers.
**Option C: Specific coach, specific service (recommended for this example)**
Select **"Specific coaches"** → check the coach → click the expand arrow next to their name → check only **"Private Lesson — 1 Hour"**.
This ensures the pass only covers 1-hour private lessons and only with coaches you chose. If the member books a 90-minute lesson or a different coach, the pass won't apply — they pay full price.
Click **Create Booking Pass**.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. How many days in advance you’ll issue them (Lead Time) - e.g. your members can book 7 days in advance, then they’ll need to have passes 7 days in advance before the new month/week starts.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many passes you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A VIP member books a 1-hour private lesson with Coach Sarah
2. The system finds an available lesson pass and applies it
3. The lesson fee is waived — the pass is consumed
4. If the member books another lesson that month, they pay full price
5. If the member tries to book a 90-minute lesson with Sarah, the pass doesn't apply (wrong service)
6. If the member books with a different coach, the pass doesn't apply (wrong coach)
7. On the 1st of next month, a new pass is allocated automatically
***
Variations [#variations]
**Any coach:** Use "All coach lessons" in Coach Restrictions to let the pass work with any coach at the club. Good for general lesson credits.
**Multiple coaches:** Check several coaches under "Specific coaches." The pass applies to any of the selected coaches.
**All services for a coach:** Select the coach but leave all services unchecked — the pass covers any service that coach offers, not just one specific type.
**Discount instead of free:** Change the Redemption Mode to "Percentage Discount" (e.g., 50% off) or "Fixed Discount" (e.g., $20 off) for a partial discount on lessons instead of a fully free lesson.
***
Key Points [#key-points]
* **"By Hours" is not available for Coach passes** — use "Whole Lesson" instead. Each lesson consumes one pass regardless of duration.
* Service-level restrictions prevent misuse — if the membership includes 1-hour lessons, restricting to the "Private Lesson — 1 Hour" service means the pass can't be used for more expensive 90-minute sessions
* Coach passes don't support time-of-day restrictions — coach scheduling is managed through the coach's own availability settings
* Unused passes expire at the end of the month unless you check **"Never expires"** in the allocation rule
# Creating a Free Pass for Events with a Specific Tag
**Example:** Members get 1 free "Youth Program" class per week.
***
Prerequisites [#prerequisites]
Before creating this pass, make sure you've created the event tag you want to use:
1. Go to **Events → Tags**
2. Create a tag (e.g., "Team Practice", "Beginner", "Youth Program")
3. Assign the tag to the relevant events
See [Event Tags](/help/facility-operators/events-and-programs/event-tags) for details on creating and assigning tags.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Event that it applies to.
5. Choose Whole Event/Reservation
6. Choose Pass Holder Only as a user type that it can be applied to.
7. If you want your members to share it with their family members, toggle on this setting:
8. Under **Event Restrictions**, enter the tag you want the pass to be applied to. In this case the pass will be applied to all events with the tag “Youth Program”
Click **Create Booking Pass**.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. Choose how many days in advance the passes should be issued (Lead Time). For example, if members can book 3 days in advance, the passes should be issued 3 days before the start of the new week or month. If passes are issued weekly, also select the day of the week when they should be allocated.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many passes you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A member joins an event tagged "Group Fitness"
2. The system finds an available pass with that tag restriction and applies it
3. The event fee is waived — the pass is consumed
4. If the member joins another "Group Fitness" event that same week, they pay full price
5. If the member joins an event without the tag (e.g., a regular Open Play), the pass is not used
6. Next Monday, a new pass is allocated automatically
***
How Tag Matching Works [#how-tag-matching-works]
* The pass applies to any event that has **any** of the selected tags
* If you select multiple tags (e.g., "Youth Program" and "Yoga"), the pass applies to events with either tag
* If you also check event types (e.g., Clinic), the pass applies to events matching the event type **OR** the tag — it's OR logic, not AND
***
Variations [#variations]
**Multiple tags:** Select several tags to make the pass cover a broader set of events — e.g., "Beginner" and "Intermediate" to cover all non-advanced classes.
**Tag + event type:** Check both a tag and an event type for maximum flexibility. For example, check "Clinic" event type and "Beginner" tag — the pass covers all clinics OR any event tagged "Beginner."
**Monthly instead of weekly:** Change the frequency to "Month(s)" for a monthly allowance instead.
***
Key Points [#key-points]
* Only events with the matching tag are covered — untagged events are not affected
* Remember to tag your events consistently — if an event isn't tagged, the pass won't apply even if it's the right type of event
* Tags use OR logic: selecting multiple tags means any one of them qualifies the event
* Unused passes expire based on the validity period unless you check **"Never expires"**
# Creating a Free Reservation Pass
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Event that it applies to.
5. Choose Whole Event/Reservation
6. Choose Pass Holder Only as a user type that it can be applied to.
7. If you want your members to share it with their family members, toggle on this setting:
8. Under **Event Restrictions**, check only **Reservations**. Leave all event types (Open Play, Clinic, etc.) unchecked — this pass should only apply to court reservations.
Click **Create Booking Pass**.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. How many days in advance you’ll issue them (Lead Time) - e.g. your members can book 7 days in advance, then they’ll need to have passes 7 days in advance before the new month/week starts.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many passes you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A Premium member books a court reservation
2. The system finds an available free reservation pass and applies it
3. The booking fee is waived — one pass is consumed (e.g., 4 → 3)
4. After all 4 passes are used, the member pays the regular court fee
5. On the 1st of next month, 4 new passes are allocated automatically
Members can see their remaining passes in **My Profile → Booking Passes**.
***
Key Points [#key-points]
* The pass covers the full reservation regardless of duration — a 60-minute and 90-minute booking each consume one pass
* If you want duration-based passes instead (e.g., 5 hours of court time), see [Create a Free Court Hours Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass)
* Only court reservations are covered — Open Play, clinics, and other events are not affected
* Unused passes expire at the end of the month unless you check **"Never expires"** in the allocation rule
# Creating a Guest Pass
**Example:** Gold members get 3 free guest passes per month.
***
Step 1: Create the Pass Template [#step-1-create-the-pass-template]
1. Go to **Booking Passes page**
2. Click **Create Booking Pass**
3. Enter the name and the description of the pass (optional)
4. Pick Event that it applies to.
5. Choose Whole Event/Reservation
6. Choose Guest Only as a user type that it can be applied to.
7. Leave **Family Sharing** off — guest passes apply to guests, not family members.
8. Under **Event Restrictions**, select which event types guests can attend — for example, check **Reservations** and **Open Play**.
Click **Create Booking Pass**.
***
Step 2: Create the Allocation Rule [#step-2-create-the-allocation-rule]
Now set up automatic allocation so members get passes when their membership activates.
1. Go to **Booking Passes → Allocation Rules**
2. Click **Create Rule**
Use this form to choose who will receive these passes, when they’ll be granted, and how often they’ll be issued.
1\. Fill out the name and the description (optional)\
2.Select the memberships and plans these passes should apply to.
3\. Define how often you will grant those passes - e.g. every month, or every week etc.\
4\. How many days in advance you’ll issue them - e.g. your members can book 7 days in advance, then they’ll need to have passes 7 days in advance before the new month/week starts.\
5\. If you check “Allocate for the current ongoing interval”, it’ll create the passes for he current period. Otherwise, it will start generating passes from the next month/week.
6\. Under **Booking Passes**, click **Add a booking pass** and configure how many passes you want to give per certain period.
Click **Save**.
***
How It Works for Members [#how-it-works-for-members]
1. A Gold member creates a reservation and adds a guest
2. The system checks for available guest passes
3. If the member has passes remaining, the guest's fee is waived
4. One pass is consumed — remaining uses go down (e.g., 3 → 2)
5. If all 3 passes are used up, the guest pays full price
6. On the 1st of next month, 3 new passes are allocated automatically
***
Key Points [#key-points]
* **Guest Only** user type means the pass only covers guests — the member's own participation is unaffected
* Unused passes expire at the end of the month (based on the 1-month validity period)
* To let unused passes carry over, check **"Never expires; unused passes accumulate"** in the allocation rule
* Guest passes work for both reservations and events — control which types via the Event Restrictions checkboxes
# Creating a Pass Package
**Use cases:**
* A "10-Pack of Court Bookings" that anyone can buy
* A "Beginner Bundle" with 5 clinic passes and 3 court hours
* A "Private Lesson Package" with 5 lessons with a specific coach
***
Step 1: Create the Booking Pass Templates First [#step-1-create-the-booking-pass-templates-first]
Before creating a package, you need the booking pass template(s) that will be included. If you haven't created them yet, go to **Booking Passes → Booking Passes** and create the templates you need.
See the most popular individual pass guides for details:
1. [Guest pass](/help/facility-operators/booking-and-guest-passes/creating-a-guest-pass)
2. [Free reservation pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass)
3. [Free court hours pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass)
4. [Free event pass](/help/facility-operators/booking-and-guest-passes/create-a-free-event-pass)
5. [Free event with specific event tag pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-pass-for-events-with-a-specific-tag)
6. [Free lesson pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-lesson-pass)
> You only need the **pass templates** — you do NOT need allocation rules for packages. The package itself handles allocation on purchase.
***
Step 2: Create the Pass Package [#step-2-create-the-pass-package]
1. Go to **Products → Add Product**
2. At the top, you'll see two options: **General Product** and **Pass Package**. Select **Pass Package**.
***
Product Details [#product-details]
| | FieldDescription |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| **Name** | The product name — visible to admins and customers (e.g., "10 Private Lessons Package") |
| **Internal description** | Notes for your team only — not shown to customers |
| **Category** | Optional — organize products by category (e.g., "Packages", "Passes"). You can create new categories from the dropdown. |
***
Product Image [#product-image]
Upload an optional image to showcase the package on your store page. Images are cropped to square format, max 5MB.
***
Sales Channels [#sales-channels]
Choose where the package can be purchased:
| | Channel Description |
| ---------------- | ---------------------------------------------------- |
| **Online Store** | Visible to customers on your club's store page |
| **POS** | Available for sale at the point of sale (front desk) |
Both channels can be enabled at the same time.
If you enabled the “Online Store” channel, your customers will see it on the Store page, and will be able to purchase from the app or website:
***
Customer Description [#customer-description]
This description is visible to customers on the store page and payment link. Use it to explain what's included in the package — e.g., "Includes 10 court booking passes, valid for 3 months."
***
Pricing [#pricing]
| | FieldDescription |
| -------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Price** | The package price (e.g., $99.00) |
| **Sales Tax** | Uses your club's default tax rate. Toggle "Use custom sales tax" to override. |
| **Rule set-based pricing** | Optional — set different prices for different membership rule sets (e.g., members pay $79, non-members pay $99) |
***
Booking Passes [#booking-passes]
This is where you configure what's included in the package.
Validity Period [#validity-period]
Set how long the passes remain valid after purchase:
* Enter an amount and unit (e.g., **3 months**, **30 days**, **1 year**)
* Or check **"Never expires"** if passes should last indefinitely
This validity period applies to **all passes** in the package.
Adding Passes [#adding-passes]
Click **"Add Pass"** to add a booking pass to the package. For each pass, configure:
| | FieldDescription |
| --------------------- | ----------------------------------------------------------------------------------- |
| **Booking Pass** | Select the pass template from the dropdown |
| **Number of Uses** | How many times the pass can be used (e.g., 10). Leave empty for unlimited. |
| **Minutes Available** | For "By Hours" passes only — the total minutes in the pool (e.g., 600 for 10 hours) |
You can add **multiple passes** to a single package. For example, a "Premium Bundle" could include:
* 10 court reservation passes
* 2 guest passes
* 1 private lesson pass
Click **"Add Pass"** again for each additional pass template.
***
Deferred Start (Optional) [#deferred-start-optional]
By default, passes become active immediately on purchase. Enable **Deferred Start** to let buyers choose a future start date — useful for seasonal packages or programs that start on specific dates.
Toggle **"Enable deferred start"** to reveal the configuration:
| | FieldDescription |
| -------------------- | --------------------------------------------------- |
| **Period Type** | How start dates are determined |
| **Max Advance Days** | How far in the future buyers can choose (1–90 days) |
**Period type options:**
| | | Period TypeWhat it doesExample |
| ------------------ | --------------------------------------------------------------------- | ------------------------------------------ |
| **Calendar Week** | Buyer picks a start-of-week date. You choose which day of the week. | "Passes start every Monday" |
| **Calendar Month** | Buyer picks a start-of-month date. You choose which day of the month. | "Passes start on the 1st of each month" |
| **Calendar Year** | Buyer picks a start-of-year date. You choose the month and day. | "Passes start on January 1st" |
| **Free Date** | Buyer picks any date within the advance window. | "Start whenever you want (within 60 days)" |
When the buyer purchases the package, they'll see a date picker at checkout with the available start dates based on your configuration.
***
Step 3: Save [#step-3-save]
Click **Save** at the bottom of the form. The package is now created and available for purchase through the channels you selected.
***
Example: 10-Pack of Court Bookings [#example-10-pack-of-court-bookings]
**Scenario:** You want to sell a package of 10 court reservations for $150, valid for 3 months.
**Prerequisites:** Create a "Court Booking" pass template (Event type, Whole Event, Pass Holder Only, Reservations only) — see [Free Reservation Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass).
**Package setup:**
| | SectionConfiguration |
| ------------------------ | ------------------------------------------------------------------------------ |
| **Name** | 10-Pack Court Bookings |
| **Customer Description** | Book 10 court sessions at a discounted rate. Valid for 3 months from purchase. |
| **Sales Channels** | Online Store: ON, POS: ON |
| **Price** | $200.00 |
| **Validity Period** | 3 months |
| **Pass 1** | Court Booking — 10 uses |
| **Deferred Start** | Off (passes start immediately) |
**How it works for the customer:**
1. Customer finds the package on the club's online store
2. They purchase it for $200
3. 10 court booking passes are immediately allocated to their account
4. Each time they book a court, one pass is consumed
5. After 3 months, any unused passes expire
***
Example: Beginner Bundle [#example-beginner-bundle]
**Scenario:** A "Beginner Bundle" for $99 that includes 5 clinic passes and 3 hours of court time.
**Prerequisites:**
* A "Clinic Pass" template (Event type, Whole Event, Clinic only)
* A "Court Hours" template (Event type, By Hours, Reservations only)
**Package setup:**
| | SectionConfiguration |
| ------------------------ | ---------------------------------------------------------------------------- |
| **Name** | Beginner Bundle |
| **Customer Description** | Perfect for new players! Includes 5 group clinics and 3 hours of court time. |
| **Price** | $99.00 |
| **Validity Period** | 2 months |
| **Pass 1** | Clinic Pass — 5 uses |
| **Pass 2** | Court Hours — 180 minutes |
| **Deferred Start** | Calendar Month, Day 1, Max 60 days |
With deferred start on "Calendar Month, Day 1", the buyer can choose to start their bundle on the 1st of this month or next month.
***
Packages vs Allocation Rules [#packages-vs-allocation-rules]
| | | Pass PackagesAllocation Rules |
| -------------------------- | --------------------------------------- | ---------------------------------- |
| **How passes are granted** | One-time purchase | Automatically with membership |
| **Recurring** | No — buy once | Yes — renews on schedule |
| **Tied to membership** | No — anyone can buy | Yes — requires specific membership |
| **Sold via** | Store, POS, payment link | N/A — automatic |
| **Best for** | Drop-in packs, seasonal bundles, trials | Ongoing member benefits |
Use **allocation rules** for recurring member benefits (e.g., "Gold members get 4 free reservations every month"). Use **packages** for one-time purchases that anyone can buy.
***
Key Points [#key-points]
* Pass templates must be created **before** you can add them to a package
* The validity period applies to all passes in the package — you can't set different expiration dates for individual passes within a package
* When a package is purchased, passes are allocated immediately (unless deferred start is enabled)
* Packages appear as products in your store — customers don't need a membership to purchase them
* You can edit a package after creation, but changes won't affect already-purchased packages
* Rule set-based pricing lets you offer member discounts on packages (e.g., members pay $79, non-members pay $99)
# Creating an Allocation Rule
This is where you connect passes to memberships and define the schedule.
1. Go to **Booking Passes → Rules**
2. Click **Create Rule**
3. Configure:
Which memberships receive this pass? [#which-memberships-receive-this-pass]
Select one or more membership products. You can optionally narrow it down to specific price tiers within a product (e.g., only the "Annual" price, not the "Monthly" price).
How often are passes allocated? [#how-often-are-passes-allocated]
Set the recurrence schedule:
| | | ScheduleWhen new passes are createdExample |
| ----------- | -------------------------------- | ------------------------------------------ |
| **Weekly** | Every N weeks on a specific day | Every Monday |
| **Monthly** | Every N months on a specific day | 1st of every month |
| **Yearly** | Every N years on a specific date | January 1st each year |
| **Daily** | Every N days | Every day |
| **Never** | One-time allocation only | On membership activation, no recurring |
You can also set:
* **Start date** / **End date** — Optional bounds for when the rule is active
* **Pre-create advance days (Lead Time)** — How many days before a period starts to create the passes (e.g., 7 days ahead so members can see upcoming passes)
Which passes to allocate? [#which-passes-to-allocate]
Add one or more pass templates with their quantities:
* Select a pass template
* Set **number of uses** (e.g., 8 sessions) or leave unlimited
* Set **amount of minutes** (for minute-based passes, e.g., 600 minutes = 10 hours)
* Set **validity period** (e.g., 1 month — the pass expires at the end of the period)
* Toggle **Never Expires** if the pass should stay valid indefinitely.\
**Note:** If this pass is issued on a recurring basis, any unused passes will roll over into the next period.
You can add multiple pass templates to a single rule. For example, a "Premium" membership rule might allocate both "8 Open Play Sessions" and "50% Off Clinics" every month.
Preview and Confirm [#preview-and-confirm]
Before creating the rule, a preview shows:
* How many currently eligible members will receive passes
* Which passes will be allocated
* When the first allocation will occur
Click **Confirm** to create the rule. Passes are immediately allocated to all currently eligible members.
# Creating and Managing Subscriptions
***
Subscriptions are different from memberships. A membership usually defines a user’s core access and rules, such as how far in advance they can book courts or bays, how far in advance they can view the schedule, court or bay pricing, and other membership-level benefits.
A subscription, on the other hand, gives the user additional recurring benefits on top of those membership benefits. Unlike memberships, users can have multiple subscriptions at the same time, and each subscription can provide its own set of benefits. These benefits are added alongside the user’s membership benefits, and the subscription billing cycle can be completely separate from the membership billing cycle.
Before you start [#before-you-start]
Before creating a subscription, you need to [create the **booking pass**](/help/facility-operators/booking-and-guest-passes/creating-booking-passes) that the subscription will deliver.
The booking pass is the actual benefit the subscriber will receive on a recurring basis. Once that booking pass is ready, you can attach it to a subscription product.
How to create a subscription product [#how-to-create-a-subscription-product]
1. Go to the **Subscriptions** page.
2. Click **New Subscription Product**.
3. Enter the product details:
* **Name**
* **Short description**
* **Full description** (optional)
* **Picture** (optional)
4. Choose how you want to sell the subscription:
* in the **online store** on the homepage
* through a **payment link** that you can send directly to users
Set up the subscription tier [#set-up-the-subscription-tier]
In the subscription product, add the tier details:
* **Tier name** — for example, Monthly or Quarterly
* **Price**
* **Billing frequency** — for example:
* every 1 month for a monthly subscription
* every 3 months for a quarterly subscription
You can also customize pricing:
* set a default price for non-members
* override the price for members
* set different prices for different membership tiers
Add subscription benefits [#add-subscription-benefits]
After setting up the pricing and billing cycle:
1. Click **Add Benefit**
2. Select the **booking pass** you want to include in the subscription
You can add more than one benefit if needed. This means a single subscription can include multiple booking passes, even different types of passes bundled together.
Once everything is set up, click **Create Product**.
How to add a subscriber [#how-to-add-a-subscriber]
After the subscription product is created:
1. Go to the **Subscribers** section
2. Click **Add Subscriber**
3. Search for and select the user
4. Choose which subscription to assign to them
Once added, the subscriber will appear on the Subscribers page.
Managing subscribers [#managing-subscribers]
On the **Subscribers** page, you can view and filter subscriptions by status, including:
* Active
* Past due
* Frozen
* Canceled
Clicking into a subscription lets you see its details, including:
* the next charge date
* past invoices
* payment history
* the benefits included in the subscription
* the booking passes the user received
* how many uses are left
* when the current booking pass expires for the active billing period
For example, if the subscription renews monthly, you’ll see the details for the current month. If it renews quarterly, you’ll see the details for the current quarter.
Example use cases [#example-use-cases]
Subscriptions can be used for recurring packages such as:
* 1 private lesson per month
* 4 private lessons per month
* 2 clinics per month
* 4 clinics per month
Summary [#summary]
A subscription is a recurring product that automatically charges the user on a set schedule and gives them the booking pass or passes included in that subscription. To create one, first set up the booking pass, then create the subscription product, add its pricing and billing cycle, attach the benefits, and assign subscribers.
# Creating Booking Passes
For an overview of how passes work with memberships, see Booking Passes & Auto-Assignment. For common pass configurations (guest pass, hours-per-month, coach lesson pass, etc.), see Types of Booking Passes.
***
Getting Started [#getting-started]
1. In the admin sidebar, click **Booking Passes**
2. Click the **Booking Passes** tab
3. Click **Create Booking Pass**
***
Step 1: Basic Information [#step-1-basic-information]
Every pass starts with a name and optional details.
Name (required) [#name-required]
The internal name your team uses to identify this pass. Members won't see this unless you leave Display Name empty. Choose something descriptive — e.g., "Monthly Guest Pass", "Off-Peak Court Hours", "Private Lesson Credit — Coach Sarah".
Minimum 3 characters.
Display Name (optional) [#display-name-optional]
The name members see during checkout when the pass is applied. If left blank, the internal Name is shown instead.
**When to use it:** When your internal naming is detailed (e.g., "2025 Q1 Promo — 50% Off Open Play") but you want members to see something cleaner (e.g., "50% Off Open Play").
Description (optional) [#description-optional]
Internal notes for your team. Not visible to members. Use it to document the purpose of the pass, which membership it's tied to, or any special conditions.
***
Step 2: Pass Type — Event or Coach [#step-2-pass-type--event-or-coach]
Choose what the pass applies to: Court Reservations and Events (Clinics, Open Plays etc) or Coaches Lessons.
Select the appropriate type. **This cannot be changed after the pass is created**, so choose carefully.
***
Step 3: Redemption Mode [#step-3-redemption-mode]
The redemption mode determines how the pass is consumed when used.
Whole Event / Whole Lesson (default) [#whole-event--whole-lesson-default]
One pass = one booking. Each time the member joins an event or books a lesson, one pass is consumed regardless of the event's duration.
**Best for:** Session-based passes like "4 open play sessions per month" or "2 private lessons per month".
By Hours (Event passes only) [#by-hours-event-passes-only]
The pass holds a pool of hours. Each booking deducts the event's duration from the pool. For example, a 10-hour pass used for a 90-minute booking has 8.5 hours remaining.
**Best for:** Flexible court time passes where members can split their hours across multiple bookings of varying lengths.
**Note:** The hour pool is set when you create the allocation rule, not on the template itself. The template just defines the redemption mode.
Percentage Discount [#percentage-discount]
The pass provides a percentage off the booking price each time it's used. Enter the discount percentage (0.01%–100%, up to 2 decimal places).
**Best for:** Membership perks like "20% off all clinics" or "50% off lessons".
Fixed Discount [#fixed-discount]
The pass provides a fixed dollar amount off the booking price. Enter the discount amount (minimum $0.01).
**Best for:** Flat-rate discounts like "$10 off any court reservation" or "$25 off private lessons".
> **Important:** The redemption mode cannot be changed once passes have been allocated to members or have redemption history.
***
Step 4: User Type — Who Can Use the Pass [#step-4-user-type--who-can-use-the-pass]
This controls whether the pass applies to the pass holder, their guests, or both.
Both Pass Holder and Guests (default) [#both-pass-holder-and-guests-default]
The pass can be used by the member themselves and by any guests they add to events or reservations.
Pass Holder Only [#pass-holder-only]
Only the member who owns the pass can use it. Guests they invite are not covered.
Guest Only [#guest-only]
The pass only applies to guests — not the member themselves. This is the key setting for creating **guest passes**. When a member adds a guest to an event or reservation, the guest's fee is covered by this pass.
**Tip:** To give members a clean setup, create two separate passes: a "Pass Holder Only" pass for their own sessions and a "Guest Only" pass for bringing friends — each with its own allocation limit.
***
Step 5: Family Sharing [#step-5-family-sharing]
Toggle **"Can be redeemed by family members"** to allow all linked family members to use the pass.
When enabled:
* Every family member linked to the pass holder automatically becomes a pass holder too
* They can use the pass independently — no need to book through the primary member
* This applies to all existing and future allocations of this pass template
When disabled (default), only the person the pass is allocated to can use it.
**Example:** A parent has a "Monthly Court Hours" pass with family sharing enabled. Their kids, who are linked as family members, can each book courts independently using the same pass pool.
***
Step 6: Restrictions [#step-6-restrictions]
Restrictions define where and when the pass can be used. The available restrictions depend on the pass type.
Event Restrictions (Event passes only) [#event-restrictions-event-passes-only]
You must select at least one event type or event tag. The form shows two columns:
**By Event Type** (left column) — check which event types qualify:
* Reservations
* Open Play
* Tournament
* League
* Clinic
* Other
**By Event Tag** (right column) — select specific tags:
* Choose from your club's event tags (e.g., "Beginner", "Youth", "Ladies Night")
Event types and tags use **OR logic** — an event qualifies if it matches any selected event type **OR** has any of the selected tags.
The **summary box** at the bottom shows a description of what qualifies so you can verify before saving.
Coach Restrictions (Coach passes only) [#coach-restrictions-coach-passes-only]
Choose how specific the pass should be:
**All coach lessons** — the pass works for any coach at the club, for any service they offer. Simple and broad.
**Specific coaches** — select exactly which coaches the pass works for. The form shows a list of all active coaches with checkboxes.
For each selected coach, you can optionally restrict the pass further to specific services:
1. Click the expand arrow next to the coach's name
2. By default, the pass works for **all services** that coach offers
3. Check specific services to limit the pass to only those (e.g., "Private Lesson — 1 Hour" but not "90 Minute Lesson")
If a coach has no services checked, the pass covers all their services. If specific services are checked, only those are covered.
**Example:** A pass restricted to two Coaches "Private Lesson — 1 Hour" service. If the member tries to book their 30-minute lesson or a different coach entirely, the pass won't apply.
Time of Day Restrictions (Event passes only) [#time-of-day-restrictions-event-passes-only]
Optionally limit when the pass can be used based on the time of the event.
1. Toggle on **"Enable time restriction"**
2. Configure allowed time windows in the schedule editor:
* Toggle which days of the week the pass is valid
* Set time ranges for each day (e.g., Monday–Friday 6:00 AM – 3:00 PM)
* Add multiple non-overlapping time slots per day
* Add date-specific overrides (e.g., block holidays)
Time restrictions are applied **in addition to** event type and tag restrictions — the event must match both to qualify.
**Example:** An "Off-Peak Court Pass" restricted to weekdays before 3 PM. A 5 PM booking won't use this pass — the member pays full price.
**Note:** Time restrictions are not available for Coach passes. Coach scheduling is managed through the coach's own availability settings.
***
Step 7: Save [#step-7-save]
Click **Create Booking Pass** at the bottom of the page. The form validates all fields — if anything is missing or invalid, it scrolls to the first error.
On success, you're redirected to the Manage page where your new pass template appears in the list.
***
What's Next After Creating a Pass [#whats-next-after-creating-a-pass]
A pass template by itself doesn't do anything — you need to **allocate** it to members. There are two ways:
1. **Manual allocation** — Go to a member's profile and allocate the pass directly
2. **Allocation rules** — Set up automatic allocation tied to a membership plan. When a member activates that membership, the pass is automatically allocated. See Booking Passes & Auto-Assignment for details.
***
Editing an Existing Pass [#editing-an-existing-pass]
Go to **Booking Passes → Manage** and click on a pass template to edit it.
Most fields are editable at any time, with two exceptions:
* **Pass Type** (Event vs Coach) — locked after creation
* **Redemption Mode** — locked once the pass has been allocated to any member or has redemption history
A yellow warning box appears on locked fields explaining why they can't be changed.
***
Tips [#tips]
* **Name passes clearly** — admins will see these names in allocation rules, reports, and member profiles. Use descriptive names like "Gold — 10hr Court Pass" rather than "Pass 1".
* **Use Display Name for clean member-facing labels** — keep internal names detailed for your team, and set a short Display Name for what members see at checkout.
* **Family sharing shares the pool, not individual allocations** — if a pass has 10 hours and family sharing is on, the entire family draws from the same 10-hour pool.
* **Test restrictions with the summary box** — the green/amber summary at the bottom of the Event Restrictions section shows exactly which events qualify. Verify it before saving.
* **You can always add restrictions later** — start simple. If a "Whole Event" pass for all event types is too broad, you can edit it and add tag or time restrictions without affecting existing allocations.
* **Combine with allocation rules for automation** — the real power of passes comes from automatic allocation with memberships. Create the template here, then set up an allocation rule to deliver it when members activate their plan.
# Booking & Guest Passes
Booking passes are member benefits: free court time, event entries, lessons or guest visits that renew on a schedule. Start with what passes are, then create templates, allocation rules and packages.
Articles [#articles]
* [What Are Booking Passes?](/help/facility-operators/booking-and-guest-passes/what-are-booking-passes) — Booking passes are benefits that members receive as part of their membership — things like "4 open play sessions per month", "10 hours of court time", "20% off clinics", or "unlimited drop-in access".
* [Redeeming Booking Passes / Guest Passes](/help/facility-operators/booking-and-guest-passes/redeeming-booking-passes-guest-passes)
* [Creating Booking Passes](/help/facility-operators/booking-and-guest-passes/creating-booking-passes) — This guide walks you through creating a booking pass template step by step.
* [Creating an Allocation Rule](/help/facility-operators/booking-and-guest-passes/creating-an-allocation-rule)
* [Auto-Allocating with Memberships](/help/facility-operators/booking-and-guest-passes/auto-allocating-with-memberships)
* [Creating a Guest Pass](/help/facility-operators/booking-and-guest-passes/creating-a-guest-pass) — Give your members a set number of free guest visits per month.
* [Creating a Free Reservation Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass) — Give your members a set number of free court reservations per month.
* [Creating a Free Court Hours Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass) — Give your members a pool of free court hours per month.
* [Create a Free Event Pass](/help/facility-operators/booking-and-guest-passes/create-a-free-event-pass) — Give your members a set number of free event entries per week/month.
* [Creating a Free Pass for Events with a Specific Tag](/help/facility-operators/booking-and-guest-passes/creating-a-free-pass-for-events-with-a-specific-tag) — Give your members free access to events tagged with a specific category — like a skill level, age group, or program name.
* [Creating a Free Lesson Pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-lesson-pass) — Give your members free private lessons with a specific coach.
* [Create a Family-Shared Pass](/help/facility-operators/booking-and-guest-passes/create-a-family-shared-pass) — Let an entire family share a single pass pool.
* [Creating a Pass Package](/help/facility-operators/booking-and-guest-passes/creating-a-pass-package) — A Pass Package is a product that bundles one or more booking passes together.
* [Creating and Managing Subscriptions](/help/facility-operators/booking-and-guest-passes/creating-and-managing-subscriptions) — A subscription lets you give users recurring benefits on a set schedule, such as every month or every quarter.
# Redeeming Booking Passes / Guest Passes
There are 3 types of booking passes:
1. Passes for you only — they allow you a certain number of free court reservations and/or participations in Open Plays, Clinics etc. or a certain number of hours.
2. Passes that you can share with your family members
3. Guest Passes — they allow to bring certain number of guests for free.
Let’s see how to redeem them with one click.
Using a booking pass for yourself [#using-a-booking-pass-for-yourself]
1. First, you choose the time and the court as usual or sign up for an event.
2. If you have any passes applicable to the reservation or this event you’ll see **"Apply Booking Pass"** checkbox. You can uncheck it if you prefer to not use it this time.
3. Once selected, the total will update to $0 (or reduced if partial coverage).
4. The booking pass usage count will update automatically.
***
Using a booking pass for you family member [#using-a-booking-pass-for-you-family-member]
1. First, you choose the time and the court as usual or sign up for an event.
2. If you have family members linked to your account, you’ll see a dropdown menu that lets you select either yourself or a family member when signing up for an event or making a reservation.
3. Pick any family member and the booking pass will be applied automatically if it can be shared with the family
Using guest passes [#using-guest-passes]
1. Pick the time and the court as usual
2. Add guests
3. If you have any guest passes, they’ll be applied automatically. You can always uncheck those boxes if you don’t want to use your guest pass this time
See how many booking passes left [#see-how-many-booking-passes-left]
You can always see how many booking passes you have left, and the redemption history in your profile.

That’s it! [#thats-it]
Booking passes make it easy for you and your guests to enjoy free or discounted play with just one click. You’ll always see how many passes you have left, and everything updates automatically at checkout.
If you ever have questions about your booking passes or run into issues, feel free to contact your club or reach out to OpenCourt Support [support@getopencourt.com](mailto:support@getopencourt.com)
# What Are Booking Passes?
Why Clubs Need This [#why-clubs-need-this]
Most clubs sell memberships that include specific benefits beyond just being a member. For example:
* **"Gold Membership"** includes 8 open play sessions per month
* **"Premium Plan"** includes 10 hours of court time per month plus 50% off clinics
* **"Youth Program"** includes 4 group clinic sessions per month
* **"Basic Membership"** includes 2 free court bookings per week
Without booking passes, admins would need to manually track how many sessions each member has used, check eligibility at every booking, and reset counters at the start of each period. With booking passes, all of this happens automatically:
1. Member's membership activates → passes are created
2. Member books an event → a pass is consumed
3. New month starts → fresh passes are allocated
4. Member cancels their membership → remaining passes are archived
Types of booking passes [#types-of-booking-passes]
1. [Guest pass (e.g. members get 3 guest passes per month)](/help/facility-operators/booking-and-guest-passes/creating-a-guest-pass)
2. [Free reservation pass (e.g. members get 4 free reservations a month)](/help/facility-operators/booking-and-guest-passes/creating-a-free-reservation-pass)
3. [Free court hours pass (e.g. members get 5 free hours for court bookings per month)](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass)
4. [Free event pass (e.g. members get 1 free Open Play a week or 1 Clinic a week)](/help/facility-operators/booking-and-guest-passes/create-a-free-event-pass)
5. [Free event with specific event tag pass (e.g. members get 1 free specific group class per week)](/help/facility-operators/booking-and-guest-passes/creating-a-free-pass-for-events-with-a-specific-tag)
6. [Free lesson pass (e.g. members get 1 free 1hr private lesson per month)](/help/facility-operators/booking-and-guest-passes/creating-a-free-lesson-pass)
# Common questions about your branded app
Who owns the app and the developer accounts? [#who-owns-the-app-and-the-developer-accounts]
You do. The App Store and Google Play require an app to be published under the business that owns it, so the accounts are registered to your company and you're the legal owner. OpenCourt builds, submits, and maintains the app as an invited **admin** on your accounts — not as the owner.
What do we have to do to keep the app live? [#what-do-we-have-to-do-to-keep-the-app-live]
Two things, and both are yours because the stores only let the account's owner do them (the **Account Holder** on Apple, the **account owner** on Google):
* **Keep a valid card on file and pay Apple's $99/year renewal.** If the renewal fails, Apple removes your app from sale until it's paid. (Google's $25 is one-time.)
* **Accept new store agreements promptly.** Apple and Google issue updated agreements a few times a year; until the owner accepts, we can't ship updates and Apple may eventually pull the app.
We'll flag what we can see, but we can't pay your renewal, accept agreements, or contact Apple for you — those are tied to your account's owner. Watch for the stores' emails, and loop us in if anything looks off.
Do we pay Apple or Google a cut of our sales? [#do-we-pay-apple-or-google-a-cut-of-our-sales]
No. Payments in your app run through OpenCourt and Stripe — not Apple's or Google's in-app billing — so there's no 15–30% store commission and no payout bank account or tax forms to set up with the stores. You still pay the flat membership fees (Apple $99/year, Google $25 once) for the right to publish the applications under your business name.
Why does Apple ask for a photo ID and a phone call? [#why-does-apple-ask-for-a-photo-id-and-a-phone-call]
Both stores verify the real business behind an app. Apple checks a government photo ID and your authority to act for the company (a "binding authority" check, sometimes a quick call); Google checks your D-U-N-S, ID, and registration documents. It's a one-time step at setup.
How long until our app is live? [#how-long-until-our-app-is-live]
The **D-U-N-S number** sets the pace — if you need a new one, allow about a week via Apple’s lookup tool. Once your accounts exist, building, branding, and store review usually take a few more days per store.
Our app disappeared or stopped updating — what happened? [#our-app-disappeared-or-stopped-updating--what-happened]
Almost always one of the two maintenance items above: a **lapsed renewal** (Apple pulls the app until you renew) or an **unaccepted agreement** (updates stop until the owner accepts it). Sign in to [App Store Connect](https://appstoreconnect.apple.com) or [Play Console](https://play.google.com/console), clear the notice (renew your card or accept the agreement), and tell us — we'll confirm everything's back. If neither applies, reach out — occasionally a store flags an app during review and we'll work it through with you.
What happens if we stop working with OpenCourt? [#what-happens-if-we-stop-working-with-opencourt]
The accounts and the app are yours. We hand over full control and remove our access — nothing is locked to OpenCourt. Apple and Google both support transferring ownership to your own staff.
# Create your Apple Developer account and invite OpenCourt
Your branded app is published on the App Store under **your business's name**, not OpenCourt's. Apple requires the business whose content is in the app to own the developer account that submits it — so you create the account, then invite us in. After that we handle the build, submission, and every update. You won't touch it again except to renew once a year and accept the occasional Apple agreement.
Budget **2–4 weeks** end to end. This is the longest-lead item in your app launch and none of it can be rushed, so start it the day you sign with us.
Enroll as a **Company / Organization**, not an Individual — an Individual account puts a personal name on your App Store listing instead of your company's, and only an organization account lets you add OpenCourt to your team. Use your exact registered legal name — Apple rejects trading names and DBAs.
Before you begin — gather these [#before-you-begin--gather-these]
* **Your legal entity name**, exactly as registered — including the suffix (Inc., LLC, GmbH). Not your DBA, not the name on your sign. This becomes the "seller" name on your App Store listing.
* **Your D-U-N-S number** — a free, nine-digit business ID Apple uses to verify your company. You may already have one. Look it up (or request one free) with [Apple's D-U-N-S lookup tool](https://developer.apple.com/enroll/duns-lookup/) — through Apple's tool a new number takes about **5 business days**, plus 2 more for Apple to sync it. [See our D-U-N-S guide](/help/facility-operators/branded-app/get-your-d-u-n-s-number). **This is the longest-lead step, so do it first.**
* **An Apple Account with two-factor authentication turned on**, registered with the enroller's **legal** first and last name — not a nickname, not the company's name. (Turning on two-factor authentication requires an Apple device, and it's different from Apple's older "two-step verification.")
* **A work email on your company's own domain** ([you@yourcompany.com](mailto:you@yourcompany.com)). Gmail/Yahoo/Outlook addresses are not accepted. Apple emails a one-time code to it mid-flow.
* **A live website** on that same domain. A Facebook page, an Instagram profile, a "coming soon" placeholder, or a registrar parking page will all be rejected.
* **A phone number** Apple can reach you on.
* **Signing authority** — the person enrolling must be able to legally bind the company to contracts (owner/founder, executive, or a delegated signatory).
* **Documents, scanned and ready** (Apple asked for all three on our last run): your government-issued photo ID, proof you work for the company (employment verification), and **one** business document for the entity — Articles of Incorporation, business license, Certificate of Formation, charter documents, notarized partnership papers, or a reseller/vendor license. *Colorado and Florida only:* E-File Articles of Incorporation **and** Certificate of Status. *Nonprofits:* also your IRS tax documents.
* **USD 99** for the annual membership — you don't pay until Apple approves you.
Nonprofit, school, or government facility? You may qualify for a fee waiver — ask us and we'll point you at the right form.
Step 1 — Register as an Apple developer [#step-1--register-as-an-apple-developer]
Go to [developer.apple.com/register](https://developer.apple.com/register/). This is the free Apple developer registration — the front door to enrollment, not the paid membership itself.
Click **Continue**. You'll be taken to the Apple sign-in screen.
Step 2 — Create the company's Apple Account (or sign in) [#step-2--create-the-companys-apple-account-or-sign-in]
If your company already has an Apple Account it wants to use, sign in. Otherwise click **Create Your Apple Account**.
Use a fresh Apple Account tied to a company email, not someone's personal one. This account becomes the legal owner of your app. It must be registered in the name of the person authorized to accept Apple's agreements — Apple's later identity check compares this name against the documents you submit.
Step 3 — Fill in the account details [#step-3--fill-in-the-account-details]
Enter the authorized person's **legal** first and last name, country/region, birthday, the company email address, and a password. Apple emails a verification code to that address — enter it to confirm the email, finish creating the account, and turn on two-factor authentication if prompted.
First and last name must be the person's **legal** name — no nicknames, and never the company's name in the name fields. Getting this wrong is one of the most common causes of a delayed approval.
Step 4 — Agree to the Apple Developer Agreement [#step-4--agree-to-the-apple-developer-agreement]
Once your account is created and you're signed in, Apple shows the Apple Developer Agreement. Read it, choose whether you'd like marketing emails (either is fine), and click **Agree**.
Step 5 — Skip the profile prompt [#step-5--skip-the-profile-prompt]
Apple offers to set up a personalized "developer profile." You don't need it for this — click **I'm not interested** (or "Remind me later").
Step 6 — Start the enrollment [#step-6--start-the-enrollment]
On your Account page, find the **Join the Apple Developer Program** box and click **Enroll today**.
Step 7 — Continue enrollment on the web [#step-7--continue-enrollment-on-the-web]
Apple suggests enrolling through the Apple Developer app, but the web works fine. Click **Continue enrollment on the web**.
Step 8 — Confirm your personal information [#step-8--confirm-your-personal-information]
Enter the authorized person's **legal name** (as shown on their government-issued ID), phone number, and address.
**You can't change your name after you click Continue**, so get it exactly right. Apple will ask this person for a photo ID later in the process — the name here must match that ID.
Step 9 — Select "Company / Organization" [#step-9--select-company--organization]
Under **I develop apps as**, choose **Company / Organization**.
**This is the most important choice in the whole process.** Picking Individual puts a personal name on your App Store listing instead of your company's, and switching afterward means a support ticket and a manual migration. Choose Company / Organization.
Apple then lists what you'll need to finish — legal entity status, authority to sign, a website, a work email, and a D-U-N-S number (with a **Check now** link to look one up). Click **Continue**.
Step 10 — Enter your legal entity name and D-U-N-S number [#step-10--enter-your-legal-entity-name-and-d-u-n-s-number]
* **Legal Entity Name** — include the entity type (Inc., LLC, GmbH). Apple's own hint: *"Include the entity type, such as Inc., LLC, GmbH, etc."*
* **D-U-N-S® Number** — the nine digits from your lookup.
* Solve the image captcha (letters aren't case-sensitive; you can switch to audio or request a different image).
Click **Continue**.
Type the name exactly as it appears on your D-U-N-S record — "Inc" vs "Incorporated" is enough to fail the match. Apple's sidebar also warns that sole proprietors and single-person companies in regions that don't recognize them as legal entities will be listed under the enrollee's **personal** name instead.
Step 11 — Confirm your address (pulled from Dun & Bradstreet) [#step-11--confirm-your-address-pulled-from-dun--bradstreet]
Apple pre-fills your **address, city, state, ZIP, and region straight from your D\&B record — and these fields are read-only.** You cannot type over them.
**If the address is wrong, you have to fix it at Dun & Bradstreet, not at Apple.** Use the "update your D\&B profile" link on this screen, wait for D\&B to process the change (up to 2 business days to reach Apple), then come back and continue the enrollment. This is the single most common place companies get stuck — an outdated address on a D\&B record nobody has looked at in years.
Step 12 — Website, phone, signing authority, and work email [#step-12--website-phone-signing-authority-and-work-email]
Scroll down and fill in:
* **Website** — your company's public site, on your own domain.
* **Phone Number** — with country code.
* **Confirm your signing authority** — pick one: *"I am the owner/founder and have the authority to bind my organization to legal agreements"* or *"My organization has given me the authority to bind it to legal agreements."*
* **Your Work Email** — must use your organization's domain. Click **Send code**, then enter the one-time code Apple emails you. Continue stays greyed out until the code is verified.
Step 13 — Save your Enrollment ID [#step-13--save-your-enrollment-id]
You'll see **"Your enrollment is being processed"** with an **Enrollment ID** and a read-only summary of everything you submitted. Apple's message: *"Once we verify your authority to sign legal agreements, we'll email you with instructions on how to complete your enrollment."*
**Write the Enrollment ID down and send it to us.** Every support request and every email from Apple references it, and it's the fastest way to unstick a stalled enrollment.
Step 14 — Send Apple your documents [#step-14--send-apple-your-documents]
Expect an email within a few days saying Apple **can't verify your identity and your association with the enrolling entity**, asking for documents. This is routine — it is not a rejection. Ours read:
*"Please provide a copy of the following documents so we can continue processing your enrollment: Applicant's government-issued photo ID; Applicant's employment verification; One of the following business documents for \[YOUR COMPANY]: Articles of Incorporation, Business license, Certificate of Formation, Charter documents, Partnership papers (must be notarized), Reseller or vendor license. For Colorado and Florida only: E-File Articles of Incorporation and Certificate of Status. And IRS tax documents for Non Profit/Not-for-profit Organizations."*
Upload at [developer.apple.com/contact/file-upload](https://developer.apple.com/contact/file-upload/).
Enter your name, then add one file at a time with **Choose file**, and **use the Notes field to label each one** ("Government issued ID", "Company articles of organization"). Click **Add another file** for each additional document, then **Continue**.
* Accepted formats: **JPG, PNG, TIFF, PDF**
* **Max 5 MB per file** — phone photos of documents often exceed this; compress them first
* Documents must be in English, Spanish, French, Italian, German, Brazilian Portuguese, Chinese, Japanese, or Korean. Anything else needs a solicitor-certified English translation.
Apple may also email that it needs to **speak with you by phone** to verify your authority — that's routine too, not a problem. You request the call yourself: go to Apple Developer Support → Contact Us → Membership and Account → Program Enrollment → Phone → "Call Me." The phone option only appears during Apple's US business hours; outside those, use the email form and ask for a callback with your number and timezone.
Step 15 — Approval, license agreement, and payment [#step-15--approval-license-agreement-and-payment]
Once Apple verifies everything, you'll get an email with next steps: review and accept the Apple Developer Program License Agreement, then purchase the **USD 99** annual membership with your card. Organizations can't pay before approval, so this email is the green light.
**Turn on auto-renew.** If the membership lapses, Apple removes your app from the App Store until it's renewed. If you don't get a membership confirmation within 24 hours of paying, contact Apple Developer Support with your Enrollment ID.
Step 16 — Invite OpenCourt to your account [#step-16--invite-opencourt-to-your-account]
Once your membership is active, add us so we can build and publish your app:
1. Open [App Store Connect](https://appstoreconnect.apple.com) and go to **Users and Access → People**.
2. Click the **+** button above the list of users.
3. Enter **[apps@getopencourt.com](mailto:apps@getopencourt.com)** and assign the **Admin** role.
4. Make sure every item in **Access to Certificates, Identifiers & Profiles** is checked — we need it to create the signing certificates and provisioning profiles your app requires. Without this, we won’t be able to publish the application.
5. Click **Invite**.
6. Switch on automated publishing: go to **Users and Access → Integrations → App Store Connect API** and click **Request Access**. Only the **Account Holder** (the person who enrolled) can do this.
That's your final step — there's nothing to send us. Clicking Request Access just lets your account generate publishing keys; because OpenCourt is now an Admin on your account, we create and manage that key ourselves. From here we build, submit, and update the app — send us a quick note that you're done and we take over.
Keeping your app live [#keeping-your-app-live]
After launch, two things stay yours because the stores only let the account's owner do them:
1. **Renew the membership every year** (keep a valid card on file — auto-renew is safest). A lapse pulls your app from the store until it's paid.
2. **Accept Apple's Program License Agreement updates** when they appear. Apple pushes new terms a few times a year, and until someone at your company clicks accept, we can't ship updates to your app.
Troubleshooting [#troubleshooting]
* **"Your organization is not listed as a legal entity."** Your D\&B record shows a different legal status (often sole proprietorship) or hasn't been verified. Fix it with D\&B using your business registration documents. A true single-person business has to enroll as an individual.
* **The pre-filled address is wrong and I can't edit it.** By design — see Step 11. Update your D\&B profile, wait for it to sync to Apple (up to 2 business days), then resume.
* **Apple is asking for documents.** Normal — see Step 14. Not a rejection.
* **My website got rejected.** It must be live, on your own domain, with real content and contact information. Social profiles and placeholder pages don't count.
* **Apple called and we weren't ready.** That's the routine verification call — confirm you're an owner or officer of the named company. If you missed it, request another via Contact Us (see Step 14's callout).
* **Nothing has happened in two weeks.** Contact Apple Developer Support with your Enrollment ID, or request a phone call: Contact Us → Membership and Account → Program Enrollment → Phone → "Call Me" (US business hours only; otherwise request an email callback).
* **We can't find the Request Access button.** Only the **Account Holder** (the person who enrolled) sees it — make sure you're signed in with that Apple Account.
Already have a personal Apple Developer account? [#already-have-a-personal-apple-developer-account]
If the Apple Account you sign in with already has an *individual* Apple Developer membership, Apple offers **"Change from an individual to an organization account"** instead of a fresh enrollment.
It lists the same requirements — legal entity status, authority to sign, a website, a work email, and a D-U-N-S number — with a **Check now** link to the D-U-N-S lookup. Click **Continue**.
On this path Apple requires the enroller to be the organization's **owner/founder** — stricter than a fresh enrollment, which also allows a delegated signatory. If the person who holds the personal account isn't an owner, it's cleaner to start fresh from a different Apple Account (Step 1).
From here you're back on the main flow at **Step 10**.
# Create your Google Play account and invite OpenCourt
Just like on the App Store, your branded app on Google Play is published under **your business's name**, and Google requires the business behind the app to own the developer account. You create the account, verify your organization, then invite OpenCourt in — and we handle the build, submission, and every update after that.
Two things make Google Play different from Apple:
* **The registration fee is USD 25, one time, ever** (Apple is USD 99/year).
* **Verification runs on your Google payments profile + D-U-N-S number**, and the legal details on both must match exactly — most delays come from a mismatch.
**Choose an Organization account, not a Personal one — and choose carefully, because the account type can't be changed after verification.** Only an Organization account shows your company's name (not an individual's) as the developer on Google Play, only an Organization account cleanly grants OpenCourt access, and newly created Personal accounts must first run a closed test with testers for 14 days before any app can go live — a requirement Organization accounts skip entirely. We cannot publish your app from a Personal account.
Before you begin — gather these [#before-you-begin--gather-these]
* **Your organization's legal name and address**, exactly as officially registered.
* **Your D-U-N-S number** — the same free, nine-digit business ID you used for your Apple account (Google requires it for organizations too). If you don't have one yet, [get it first](/help/facility-operators/branded-app/get-your-d-u-n-s-number) — via Apple's lookup tool it takes about 5 business days; requesting directly from Dun & Bradstreet can take up to 30 days. Your D-U-N-S legal name and address must match your Google payments profile exactly.
* **A Google Account for the company** — use a company email, not someone's personal account.
* **A private contact email + phone** Google uses to reach your organization. Verified by one-time password; not shown publicly.
* **A public developer email + phone** that *will* be shown on your Google Play listing. Also verified by one-time password. Organizations must provide both sets.
* **An organization registration document** — certificate of incorporation, business license, or VAT registration certificate, issued by a government or business registry.
* **A government photo ID** for an authorized representative (driver's license, passport, or national ID).
* **USD 25** for the one-time registration fee.
Government facility? Government agencies can sometimes verify without a D-U-N-S number — ask us and we'll flag the right path with Google before you create the account.
Step 1 — Create a Google Play Console developer account [#step-1--create-a-google-play-console-developer-account]
Go to [play.google.com/console/signup](https://play.google.com/console/signup) and sign in with the company's Google Account. When asked what kind of account you're creating, choose **Organization** — not Personal.
Step 2 — Link a Google payments profile [#step-2--link-a-google-payments-profile]
Google asks you to link a **Google payments profile** — this is how it collects and verifies your organization's legal name, address, and D-U-N-S number. Select an existing profile or create a new one.
This payments profile is used **only to verify your organization** — it's not the same thing as getting paid, and you don't have to use it for payouts. Payments in your app run through OpenCourt and Stripe, not Google's billing, so there are no payout bank accounts or tax forms to set up with Google.
Step 3 — Pay the USD 25 registration fee [#step-3--pay-the-usd-25-registration-fee]
Google charges a **one-time USD 25 fee** to register a developer account, paid with your card during signup. Unlike Apple's annual fee, this is paid once and never again.
Step 4 — Enter and confirm your D-U-N-S number [#step-4--enter-and-confirm-your-d-u-n-s-number]
Enter your nine-digit D-U-N-S number. Google looks up your business information and shows it back to you — review it carefully and select **Confirm**.
**You get a limited number of attempts to enter the D-U-N-S number correctly** — have it right before you start. And **the legal name and address on your D-U-N-S profile must match your Google payments profile exactly.** If Google later finds a mismatch, you get **28 days** to fix it before your account and apps are removed. This is the #1 place organizations get stuck — fix mismatches at Dun & Bradstreet first.
Step 5 — Add your organization and contact details [#step-5--add-your-organization-and-contact-details]
Fill in the remaining details about your organization, then provide:
* **Contact email + phone** — how Google reaches you privately. Verified by one-time password (OTP). Not shown on Google Play.
* **Public developer email + phone** — shown on your Google Play listing. Also verified by OTP. Organizations must provide both.
For phone OTP you can choose SMS or a voice call — if one fails, try the other. Use a monitored company inbox for the contact email, not a personal one, so account notices don't get lost.
Step 6 — Verify your identity and organization with documents [#step-6--verify-your-identity-and-organization-with-documents]
Google prompts you to upload official documents. The exact list depends on your country — Play Console shows the ones relevant to you. Typically:
* **An organization registration document** — certificate of incorporation, business license, or VAT registration certificate.
* **A personal photo ID** for an authorized representative (driver's license, passport, or national ID). The account owner *or* any authorized representative can provide this.
Enter the name and address exactly as they appear on the document you upload.
**Never edit, crop-to-alter, or "clean up" a document** — modified documents cause verification to fail and can get the account removed. Providing unsupported document types is the single most common verification problem, so check Play Console's accepted-documents list before uploading.
Step 7 — Wait for verification [#step-7--wait-for-verification]
Google reviews what you submitted; the account owner gets an email when verification is complete — usually within a few days. The Play Console home page shows a "we're verifying your identity" message meanwhile. When it's done, the banners disappear and your verified info appears on the Account details page.
Step 8 — Invite OpenCourt to your Play Console [#step-8--invite-opencourt-to-your-play-console]
Once your account is verified, add us so we can build and publish your app:
1. In [Play Console](https://play.google.com/console), go to **Users and permissions → Invite new users**.
2. Enter **[apps@getopencourt.com](mailto:apps@getopencourt.com)**.
3. Grant the **Admin (all permissions)** account-level permission.
4. Send the invitation, then let us know.
That's it — there's nothing else to send us. Once we accept the invitation, OpenCourt sets up automated publishing and handles building, submitting, and updating your Android app. You won't need to log in again except to accept an occasional Google agreement.
Troubleshooting [#troubleshooting]
* **I don't have a D-U-N-S number.** Get one free — [our guide shows the fastest route](/help/facility-operators/branded-app/get-your-d-u-n-s-number) (about 5 business days via Apple's lookup tool, which issues the same number Google needs; requesting directly from Dun & Bradstreet can take up to 30 days). You can't create an Organization account without one, so start immediately.
* **"Your organization name or address is no longer verified" / a mismatch banner.** Your Google payments profile and your Dun & Bradstreet profile disagree. Fix the details (usually at Dun & Bradstreet), then approve the update in Google Payments Center. You typically have 28 days before apps are restricted.
* **Verification was rejected.** The most common cause is a document mismatch — the legal name on your D-U-N-S, your photo ID, and your registration document must all match. Resubmit with consistent documents.
* **Sign-up is asking us to recruit testers.** That means a **Personal** account was created. Personal accounts must run a 14-day closed test before launching anything — create an **Organization** account instead, which skips that entirely.
* **Phone number won't verify.** Switch between SMS and voice call. If your phone system has an auto-attendant, route the OTP call to a line a person can answer.
* **We can't reach the account owner.** Only the account owner can complete verification. If they've left the company, contact Google Play support and request a deadline extension in Play Console.
After you're verified [#after-youre-verified]
Invite us (Step 8) and tell us — we take it from there: the build, the store listing, review, and every update. On Android there's **no annual renewal** (the USD 25 was one-time), but keep two things current or Google can pull your app:
1. **Your D-U-N-S / payments-profile details** — if they drift out of sync, fix promptly (you get a 28-day window).
2. **Your public developer email and phone** — these must stay reachable, and Google's occasional updated agreements need accepting.
# Get your D-U-N-S number
A D-U-N-S number is a free, nine-digit ID that Dun & Bradstreet assigns to a business. Apple and Google both require it to confirm your company is a real organization before they'll let you publish an app. You use the **same number** for both stores. *(Free. Through Apple’s lookup tool a new number takes about 5 business days; requesting directly from Dun & Bradstreet can take up to 30 days — so start here first.)*
Check whether you already have one [#check-whether-you-already-have-one]
Many companies were assigned a D-U-N-S years ago without realizing it, so look yours up before requesting a new one:
1. Open [Apple's D-U-N-S lookup tool](https://developer.apple.com/enroll/duns-lookup/) (sign in with your Apple Account). It's free and the fastest route for app publishing.
2. Enter your **legal entity name** and **address**.
3. If a match appears, that's your number — you're done. If nothing matches, request a new one in the same flow.
Use your exact registered legal name — not a trading name or "DBA." Most lookup failures come from a name that doesn't match your official business registration.
**We highly recommend using Apple’s tool for both the lookup and the request** — it’s much faster than going through Dun & Bradstreet’s own website, and the same number works for Google Play too.
Request a new one (free) [#request-a-new-one-free]
If the lookup doesn’t find your company, request a new number for free right there in the same flow. **We highly recommend requesting your D-U-N-S number through Apple’s lookup tool** — not directly from Dun & Bradstreet’s website, which is slower and easier to get wrong. You’ll provide:
* Your **legal entity name** (exactly as registered)
* Your **headquarters and mailing address**
* A **work contact** (name, phone, email)
Dun & Bradstreet may call or email to confirm details about your company, so have your registration documents handy. Through Apple’s tool, processing typically takes up to 5 business days, plus up to 2 more for the number to sync to Apple. Requesting directly from Dun & Bradstreet can take up to 30 days.
Once you have it [#once-you-have-it]
Keep your number handy — you'll enter the **same one** when you set up both your Apple Developer and Google Play accounts. Share it with us too, so we can track your setup.
Troubleshooting [#troubleshooting]
* **The lookup can't find my company.** You probably entered a trading name. Use your **exact registered legal name and address**. If it still isn't found, request a new number in the same flow.
* **It says we're a sole proprietor or not a company.** Your business may be registered as a sole proprietorship rather than a company. Contact Dun & Bradstreet to confirm or update your legal status — or reach out to us and we'll help you figure out the right path.
* **I just received my number but Apple or Google can’t find it.** Newly issued numbers take a day or two to propagate to the lookup systems — wait 48 hours and try again.
* **It's taking a long time.** Through Apple's tool, your number should arrive within about 5 business days — if it's been more than two weeks, email Dun & Bradstreet. They also sell a paid expedited option, though most companies don't need it. Requests made directly at dnb.com can take up to 30 days; D\&B sells a paid expedited option (about USD 229) for that route, but it won't speed up requests made through Apple's tool, and most companies never need it.
Next step [#next-step]
Once you have your number, continue with [**Create your Apple Developer account and invite OpenCourt**](/help/facility-operators/branded-app/create-your-apple-developer-account-and-invite-opencourt) and [**Create your Google Play account and invite OpenCourt**](/help/facility-operators/branded-app/create-your-google-play-account-and-invite-opencourt).
# Branded App
Your club's own branded (white-label) app on the App Store and Google Play. These articles walk through the accounts you set up once and the questions clubs ask most.
Articles [#articles]
* [Overview / How your branded app is published](/help/facility-operators/branded-app/overview-how-your-branded-app-is-published) — How your company's branded (white-label) app gets published under your business on the App Store and Google Play — who does what, costs, and timeline.
* [Get your D-U-N-S number](/help/facility-operators/branded-app/get-your-d-u-n-s-number) — How to find or request your free D-U-N-S number — the business ID Apple and Google require to publish your branded (white-label) app.
* [Create your Apple Developer account and invite OpenCourt](/help/facility-operators/branded-app/create-your-apple-developer-account-and-invite-opencourt) — Set up the Apple Developer account your branded (white-label) iOS app is published under, and give OpenCourt access.
* [Create your Google Play account and invite OpenCourt](/help/facility-operators/branded-app/create-your-google-play-account-and-invite-opencourt) — Set up the Google Play account your branded (white-label) Android app is published under, and invite OpenCourt.
* [Common questions about your branded app](/help/facility-operators/branded-app/common-questions-about-your-branded-app) — Answers to the questions companies ask most about their branded (white-label) app — ownership, fees, keeping it live, and timelines.
# Overview / How your branded app is published
Your business gets its own **branded app** — sometimes called a **white-label app** — on the App Store and Google Play, published **under your business**. OpenCourt builds, submits, and maintains it, but Apple and Google require the developer accounts to belong to the business that owns the app, so a few setup steps are yours. This page explains how the pieces fit together and who does what.
Apple's and Google's rules require an app to be published by the business behind it, not by a software vendor. That's why the accounts are in your name and you stay the legal owner — OpenCourt operates them for you as an invited admin.
What you do vs what OpenCourt does [#what-you-do-vs-what-opencourt-does]
| Step | You (the company) | OpenCourt |
| ------------------------------------------------------------------------- | ---------------------------- | ------------------- |
| Create the Apple & Google developer accounts | Yes — one time, we guide you | — |
| Pass identity and business verification (D-U-N-S, photo ID, Apple's call) | Yes | — |
| Pay the store fees (Apple $99/yr, Google $25 once) | Yes | — |
| Invite OpenCourt as admin and switch on automated publishing | Yes — a couple of clicks | — |
| Design, build, and brand the app | — | Yes |
| Submit to both stores and handle review | — | Yes |
| Ship updates and fixes | — | Yes |
| Keep the accounts in good standing (renewal card, new agreements) | Yes | We flag what we see |
Why the accounts have to be yours [#why-the-accounts-have-to-be-yours]
Both stores tie an app to the **legal business** that provides it — verified by your registered entity name, a D-U-N-S number, and a government photo ID of an authorized person. A software vendor can't stand in for that. The upside: your company is the named developer (the "seller") on both stores, your branding is fully yours, and the app stays with you.
What it costs [#what-it-costs]
* **Apple:** $99 per year, paid with your card.
* **Google:** $25 one time, paid with your card.
* **No payout bank or tax forms** — because payments in your app run through OpenCourt and Stripe, not the stores' in-app billing.
Registered nonprofit? Apple may waive its annual fee.
How long it takes [#how-long-it-takes]
The long pole is the **D-U-N-S number** (the free business ID both stores require). If your company already has one, setup runs in a few days per store. If you need to request one, allow about a week through Apple’s lookup tool (up to 5 business days, plus 2 to sync) — or up to a month if requested directly from Dun & Bradstreet. [Learn more about getting your D-U-N-S number here](/help/facility-operators/branded-app/get-your-d-u-n-s-number).
Set up your accounts [#set-up-your-accounts]
Use the two setup guides in this section to create your accounts and invite OpenCourt:
* [**Create your Apple Developer account and invite OpenCourt**](/help/facility-operators/branded-app/create-your-apple-developer-account-and-invite-opencourt)
* [**Create your Google Play account and invite OpenCourt**](/help/facility-operators/branded-app/create-your-google-play-account-and-invite-opencourt)
Once you're set up, see [**Common Questions (FAQ)**](/help/facility-operators/branded-app/common-questions-about-your-branded-app) for the two things that can take an app offline and how to prevent them.
# Check a customer in with the QR scanner
Check a customer in at the front desk by scanning the QR code from their OpenCourt app. *(About 2 minutes to set up your scanner; each check-in takes about a second.)*
Works on any page of the admin panel. You need a USB QR/barcode scanner plugged into your front-desk computer (any model that reads QR codes works). No scanner? Use **Find Customer** — see [Check a customer in without a scanner](#check-a-customer-in-without-a-scanner).
Before you begin [#before-you-begin]
* A USB QR scanner connected to the computer running the admin panel.
* The customer has the OpenCourt app and can open their **Check-In QR Code** (in the app under **My Profile**).
Where the customer finds their QR code [#where-the-customer-finds-their-qr-code]
The customer opens the OpenCourt app, goes to **My Profile**, and taps **Check-In QR Code**. They show that screen to your scanner.
Check a customer in [#check-a-customer-in]
1. Open the admin panel to any page — the **Today** page is a good home base.
2. Point the scanner at the customer's **Check-In QR Code** and scan. You do not need to open anything first.
3. Read the result:
* A green **Checked in** banner appears at the top of the screen with the customer's name and photo, then clears on its own. They are checked in — wave them through.
* A **Scan result** window opens showing **Needs attention** if something needs a look (see below).
What happens next [#what-happens-next]
Every check-in appears in the **Check-in** panel on your **Today** page, under **Recently checked in**, with a badge showing how it happened: **QR scanner** (you scanned them), **Self check-in** (they used a self-service QR), or **Staff** (set by hand). The header shows a running count of how many customers have checked in today.
Handle a customer who needs attention [#handle-a-customer-who-needs-attention]
When the **Scan result** window shows **Needs attention**, the reason is listed at the top — for example *No booking today*, *Waiver not signed*, or *Payment required*. The customer also drops into the **Needs attention** list in the **Check-in** panel, so they are not lost if the next person scans before you finish.
From the **Scan result** window you can:
* **Check in** a booking with one click, or open the status dropdown to set *Late arrival*, *No show*, or *Not checked in*.
* Check in each guest on the booking — every guest has their own **Check in** button and status dropdown, with their waiver and payment state shown next to their name. **Convert** turns a name-only guest into a customer account.
* **Take photo** to capture a check-in photo (upload a file or use the computer's camera).
* **Add** a note, or open the customer's full record with **View profile**.
* For someone who is not a customer of this club yet, **Add as customer** — then their check-in continues.
To come back to someone later, open the **Check-in** panel on **Today**: click **Resolve** on their card to reopen their result, or dismiss the card once they are handled. Anyone who gets checked in — by you or by any other means — clears from **Needs attention** automatically.
Check someone in early [#check-someone-in-early]
A scan only checks a customer in automatically once their check-in window opens (a set number of minutes before the booking starts — 180 by default, changed under **Settings → Check-in**). A booking whose window hasn't opened yet still appears in the **Scan result** with a **Starts in \[hours and minutes]** countdown — and its **Check in** button works. If someone arrives early and you want them in, check them in; the window only limits the automatic behavior, never you.
The bookings list is headed **\[N] bookings today**, so when a customer has more than fits on screen — a session now and a reservation tonight — the count tells you to scroll for the rest.
Check a customer in without a scanner [#check-a-customer-in-without-a-scanner]
1. Click **Find Customer** at the top of the admin panel.
2. Search by name or email and pick the customer.
3. Their **Scan result** window opens — check in their booking or handle whatever needs attention, the same as a scan.
If something goes wrong [#if-something-goes-wrong]
* **Nothing happens when I scan** — make sure the scanner is plugged in, then run the built-in test at **Settings → Check-in → Test your scanner**; the verdict names the cause and the fix (see [Set up the QR scanner](/help/facility-operators/check-in/set-up-the-qr-scanner)). The scanner's suffix setting doesn't matter — Enter, Tab, or none all work.
* **The scanner types strange characters** — run **Settings → Check-in → Test your scanner**; a **Characters came through garbled** verdict means the scanner's keyboard-country setting is mismatched. Set the scanner to a US layout with the configuration barcode in its manual, then test again.
* **"Not a customer" for someone who is a member** — you may be on the wrong club, or they used a different account. Confirm the club in the top bar, then use **Add as customer** or **Find Customer** to locate the right record.
* **The customer can't find their QR** — it is in the OpenCourt app under **My Profile → Check-In QR Code**. If they are not on the app, use **Find Customer** instead.
Related [#related]
* [Set up the QR scanner at your front desk](/help/facility-operators/check-in/set-up-the-qr-scanner)
* [Check-in reasons and troubleshooting](/help/facility-operators/check-in/check-in-reasons-and-troubleshooting)
* [Let customers check themselves in with a posted QR code](/help/facility-operators/check-in/let-customers-self-check-in)
* [Check-In & QR Scanner overview](/help/facility-operators/check-in)
* [Check-In & QR Scanner overview → Set the check-in window](/help/facility-operators/check-in#set-the-check-in-window)
# Check-in reasons and troubleshooting
Every result the **Scan result** window can show, what it means, and what to do. Use this to look up a specific reason when a scan flags **Needs attention**.
A green **Checked in** flash means the customer was all set and is already checked in — nothing to do. Everything else opens the **Scan result** window with a verdict at the top and details below.
The verdict at the top of a scan [#the-verdict-at-the-top-of-a-scan]
The colored strip at the top of the **Scan result** window states the overall outcome:
| Verdict | What it means | What to do |
| ---------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Checked in** | The customer was eligible and is now checked in. | Nothing — wave them through. |
| **Already checked in** | They already checked in today. | Nothing, unless you're re-opening to review. |
| **Ready to check in** | Re-opened, eligible, but not yet checked in (this view never checks anyone in on its own). | Use the booking's **Check in** button. |
| **Needs attention** | Something needs a look before check-in. The specific reasons are listed underneath (see below). | Handle the reason(s) listed. |
| **Not a customer yet** | The QR belongs to a real OpenCourt account that isn't a customer of your club. | Click **Add as customer** to add them and continue. |
| **No customer found** | The code didn't match anyone. | Scan the QR again. If it keeps failing, use **Find Customer**. |
| **Unrecognized code** | The scan isn't an OpenCourt customer QR. | Ask the customer to open their QR from **My Profile → Check-In QR Code** and scan again. |
Needs attention reasons [#needs-attention-reasons]
When the verdict is **Needs attention**, each reason is listed as a line under it. These are the reasons a scan can raise:
| Reason | What it means | What to do |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **No booking today** | The customer has nothing on the roster for today. | Confirm they have a reservation or are on an event. If they're a legitimate walk-in, add them to a booking or event, or take payment at the desk. |
| **Waiver not signed** | The club requires a waiver and this customer has none on file. | Click **Manage waivers** to send or record their waiver, then re-scan. |
| **Waiver expired** | Their signed waiver is past its validity. | Click **Manage waivers** to have them re-sign, then re-scan. |
| **Fee unpaid** | Money is owed on today's booking — an event or program fee, or the court fee on a reservation. The amount is shown on the booking card. | Collect payment (or have them pay in-app), then check in. |
| **Guests to check in** | The customer is checked in, but guests on their booking still aren't. | Check each guest in from their row on the booking card. |
| **Outside check-in window** | The booking is real but its window hasn't opened yet (it opens a set number of minutes before the start). | The card shows a **Starts in \[hours and minutes]** countdown — its **Check in** button works, so check them in early if you want them through. Only automatic check-in waits for the window. |
| **Marked as no-show** | The booking was already marked a no-show. | Re-open the booking's status dropdown and set **Checked in** or **Late arrival** if they did show. |
| **Check-in blocked** | Check-in isn't possible for another reason surfaced by the booking rules. | Read the booking card for the specific cause, or open the event to investigate. |
| **Booking later today at \[time]** | The customer has no booking in the check-in window right now, but has one later today. | The booking card shows a **Starts in** countdown with a working **Check in** button — check them in early, or let them scan again once the window opens. |
Waiver states on the customer card [#waiver-states-on-the-customer-card]
Separate from the reason strip, the customer's status ledger always shows a waiver row so the state is never ambiguous:
* **Waiver signed** (green) — a current, valid signature is on file.
* **Waiver expired** (amber) — a signature exists but has lapsed; matches the **Waiver expired** reason.
* **No waiver on file** (red) — the club requires a waiver and none is signed; matches the **Waiver not signed** reason.
* **Waiver not required** (muted) — the club has no active waiver, so no waiver is needed.
Payment states on a booking card [#payment-states-on-a-booking-card]
Every booking card shows an explicit payment chip:
* **Paid** — nothing owed.
* **Free — nothing due** — the booking has no fee.
* **\[amount] due** (or **Payment due**) — an amount is owed. The chip shows the amount even when the check-in is allowed (for clubs that collect at the desk), so you always know what to collect.
Booking status and the manual status dropdown [#booking-status-and-the-manual-status-dropdown]
Each booking card carries a status and a labeled dropdown to change it. The status label mirrors the situation: **Checked in**, **Ready to check in**, **Fee unpaid**, **Not checked in** (a booking whose window hasn't opened yet — it also shows a **Starts in** countdown), **Marked as no-show**, or **Check-in blocked**. The bookings list is headed **\[N] bookings today**, so you always know how many cards there are — scroll if the count is higher than what's on screen.
Open the dropdown (labeled **Change status**) to set any of:
* **Checked in**
* **Late arrival**
* **No show**
* **Not checked in**
This is the same status set the event's own participant view offers. Changing status here is quiet — it doesn't play the scan sound or re-run the verdict.
Party (group) check-in [#party-group-check-in]
When a scanned booking includes other people (a reservation with guests, or a group), each appears under the booking with their own **Check in** button and status dropdown, plus their own waiver and payment state — so you can see at a glance which guest still owes a signature or a fee. Check in the whole party from the one **Scan result** window; each person shows **Checked in** once handled.
* A guest with an OpenCourt account shows as a link — click their name to open their record.
* A name-only guest (no account) shows a **Convert** button that turns them into a customer account on the spot.
* Contact details of party members are never shown here — names and status only.
Coming back to someone later [#coming-back-to-someone-later]
Anyone flagged **Needs attention** also drops into the **Needs attention** list in the **Check-in** panel on your **Today** page, so they aren't lost when the next customer scans:
* **Resolve** re-opens that person's **Scan result** (read-only — it never checks anyone in by itself).
* **Dismiss** clears the card once you've handled them.
* The list self-heals: anyone who gets checked in by any means — you, another device, or self check-in — drops off automatically.
Source badges on Recently checked in [#source-badges-on-recently-checked-in]
The **Recently checked in** list badges each arrival by how it happened, so you can tell self-service from staffed check-ins:
| Badge | Meaning |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **QR scanner** | An automatic check-in from scanning the customer's QR at the desk (the green **Checked in** flash). |
| **Self check-in** | The customer used a posted self check-in QR. |
| **Staff** | Checked in by hand — the **Check in** button in the **Scan result** window, a **Find Customer** check-in, or a status change from the event view. |
The panel header shows a running **\[N] checked in today** count.
Related [#related]
* [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in)
* [Set up the QR scanner at your front desk](/help/facility-operators/check-in/set-up-the-qr-scanner)
* [Let customers check themselves in with a posted QR code](/help/facility-operators/check-in/let-customers-self-check-in)
* [Check-In & QR Scanner overview](/help/facility-operators/check-in)
# Choose a QR scanner for your front desk
Any USB 2D/QR scanner works with OpenCourt — there's no proprietary hardware and no per-device fee. The scanner reads the customer's Check-In QR and sends it like a keyboard, so an inexpensive model and a premium one both check customers in the same way.
Once a scanner is plugged in, scanning works from any admin page. Full setup and testing is in [Set up the QR scanner at your front desk](/help/facility-operators/check-in/set-up-the-qr-scanner).
What to look for [#what-to-look-for]
Any scanner that meets these works:
* **Reads 2D / QR codes** (not 1D-only). The Check-In QR is a 2D code.
* **Reads from a phone screen**, not just paper — customers show the QR on their phone.
* **Connects as a USB keyboard** (plug-and-play, no driver or app) — the default on virtually all scanners in this class, including the ones below. The suffix setting (Enter, Tab, or none after each scan) does not matter; OpenCourt works with all of them.
Recommended models [#recommended-models]
Four options, from a hands-free desktop stand to a professional handheld:
| Scanner | Type |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| [Tera 9700](https://www.amazon.com/dp/B0F385N2MX) or [Symcode](https://www.amazon.com/dp/B087CSV7NL) | Hands-free desktop stand · wired USB |
| [ScanAvenger Wireless](https://www.amazon.com/dp/B08DNG34CY) | Handheld · wireless / Bluetooth / USB · charging stand |
| [Tera D5100](https://www.amazon.com/dp/B07M68LS2N) | Handheld · wireless / USB |
| [Zebra DS2208](https://www.amazon.com/dp/B076KQXDQ9) | Handheld · wired USB · professional-grade |
*These are examples to point you in the right direction, not endorsements or affiliate links — we don't sell hardware. Any scanner meeting the checklist above works.*
**Choosing:** a **hands-free stand** suits a staffed desk (the customer holds their phone up — nothing to press); a **handheld** suits staff who prefer to pick up and scan; the **Zebra** is for high-volume clubs that want professional durability.
Running the admin panel on a **tablet or iPad**? Choose a Bluetooth model (like the ScanAvenger), which pairs as a keyboard; a USB-only scanner needs a compatible adapter.
If you pick a **handheld**, plan on a stand or mount too. Most clubs want the scanner resting on the counter so customers present their phone to it hands-free — without one, staff pick the scanner up for every check-in. The ScanAvenger includes a charging stand; for the Tera D5100 or Zebra, a compatible stand is an inexpensive add-on.
Configuration [#configuration]
These scanners work out of the box — no software and no settings to change. If you do want to change a default, there's no app: you scan a configuration barcode from the scanner's manual (or the setup card in the box), and the scanner beeps to confirm.
The one setting worth changing for a front desk is **always-on**. Many scanners — hands-free stand models especially — sleep after a few idle minutes, so the first scan after a quiet stretch can lag or miss. To prevent this, find the barcode for **"always on"**, **"disable sleep"**, or **"continuous / presentation mode"** in the manual and scan it once. The same manual has barcodes for an Enter suffix and keyboard layout if scans aren't registering (see [Set up the QR scanner](/help/facility-operators/check-in/set-up-the-qr-scanner)), plus a **"restore defaults"** barcode that undoes any change.
Keep the scanner's setup card or manual at the desk — it's the scanner's only control panel.
Related [#related]
* [Set up the QR scanner at your front desk](/help/facility-operators/check-in/set-up-the-qr-scanner)
* [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in)
* [Check-In & QR Scanner overview](/help/facility-operators/check-in)
# Check-In & QR Scanner
Check customers in at the door by scanning the QR code from their OpenCourt app, and track who has arrived from your **Today** page.
Scanning works from any page of the admin panel with a USB QR scanner. The check-in rules and the self check-in QR codes (for customers checking themselves in) live under **Settings → Check-in**.
How check-in works [#how-check-in-works]
A customer shows their **Check-In QR Code** (in the OpenCourt app under **My Profile**). You scan it with a USB QR scanner from anywhere in the admin panel, and OpenCourt decides in about a second whether they are all set:
* **All set** — a green **Checked in** confirmation appears briefly and clears itself. They walk through.
* **Needs attention** — a **Scan result** window opens with the reason (for example a missing waiver, an unpaid booking, or no booking today) and one-click ways to fix it.
The same check works whether the customer is checking in for a court booking, an event, or a program — and it uses the same rules as self check-in, so the front desk and self-service always agree.
The Check-in panel on Today [#the-check-in-panel-on-today]
Your **Today** page has a **Check-in** panel with two lists:
| List | What it shows |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Needs attention** | Customers who scanned but need a hand (missing waiver, payment due, no booking). They stay here until you handle them — click **Resolve** to reopen, or dismiss the card. |
| **Recently checked in** | Everyone who has checked in today, newest first, each badged **QR scanner**, **Self check-in**, or **Staff** so you can see how they arrived. |
Set the check-in window [#set-the-check-in-window]
**Check-in window** controls how early check-in opens before a booking starts, in minutes (the default is 180 — three hours). Change it under **Settings → Check-in**.
The window is a hard limit for customer self check-in only. At the front desk it governs the automatic part: a scan auto-checks-in only inside the window, and a booking later in the day shows a **Starts in \[hours and minutes]** countdown — but its **Check in** button works, so you can check an early arrival in whenever you decide.
Articles [#articles]
* [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in) — scan at the front desk, and handle anyone who needs attention.
* [Choose a QR scanner for your front desk](/help/facility-operators/check-in/choose-a-qr-scanner) — four scanners we recommend, from a budget hands-free stand to a premium handheld, and what to look for.
* [Set up the QR scanner at your front desk](/help/facility-operators/check-in/set-up-the-qr-scanner) — plug in a USB scanner and test it in about two minutes.
* [Let customers check themselves in with a posted QR code](/help/facility-operators/check-in/let-customers-self-check-in) — create a self check-in QR, choose Static or Dynamic, and set the payment and window rules.
* [Check-in reasons and troubleshooting](/help/facility-operators/check-in/check-in-reasons-and-troubleshooting) — every Needs attention reason, waiver and payment state, status, and source badge, and what to do about each.
# Let customers check themselves in with a posted QR code
Post a QR code at your club so customers check themselves in from their phones — no staff at the desk and no app to download. *(About 10 minutes for the first QR. You need the club settings permission and, ideally, a tablet to display it.)*
Self check-in is set up under **Admin → Settings → Check-in**, in the **Self check-in** section. You need the club settings permission to see it. This is the self-service side; for scanning customers in yourself, see [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in).
How self check-in works [#how-self-check-in-works]
You display a QR code at your club. A customer scans it with their phone camera, their browser opens the check-in page, and they check themselves in with one tap. It works for reservations, events, and programs the customer is on the roster for within the check-in window. Front-desk scanning and self check-in run the same rules, so the two never disagree.
Before you begin [#before-you-begin]
* The club settings permission (you can open **Settings**).
* A device to display the QR: a tablet on a stand, a printed sign, or both.
* Optional but recommended: your club's waiver is set up, so waiver-required customers are prompted to sign.
Create a self check-in QR code [#create-a-self-check-in-qr-code]
1. Go to **Admin → Settings → Check-in**.
2. In the **Self check-in** section, under **Your QR codes**, click **Add QR code**.
3. Fill in the QR code:
* **Internal label** — for your reference only (for example *Front desk* or *Court 3 entry*). Customers don't see it.
* **Title shown to customers** — appears on the display and printable flyer (for example *Self check-in*).
* **Check-in QR type** — choose *Dynamic QR* or *Static QR* (see the next section).
4. Click **Create QR code**.
New QR codes are **Enabled** by default. A disabled QR code can't be used for check-in.
Choose Static or Dynamic [#choose-static-or-dynamic]
| Type | What it is | Best for |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Dynamic QR** *(Recommended)* | The code rotates every few minutes on a tablet. An old screenshot expires, so a customer can't check in from home. | An iPad or wall display at the entrance where remote check-ins would be a problem. |
| **Static QR** | One permanent code that never changes. Print it or display it. | A poster at the desk, a sticker by the door, or a tablet you don't want to manage — anyone with a photo of it can scan it from anywhere. |
The rotation timing on a Dynamic QR (it rotates every 5 minutes and each code stays valid for 10 minutes) is set by OpenCourt and can't be changed from the admin panel. Contact support if you need different rotation timing. You can still switch a QR between Static and Dynamic yourself — except on a club's built-in default QR, where the type is **Locked on default QR codes**; add a new QR if you need a different type.
Display the QR code [#display-the-qr-code]
1. On the **Check-in** settings page, find your QR code under **Your QR codes** and click **View**.
2. Under **Deploy this kiosk** (Dynamic) or **Deploy this QR** (Static), use the option that fits your setup:
* **Open display** — opens the full-screen display page. Run this on the tablet you're mounting.
* **Copy** the **Display URL** — paste it into the tablet's browser, then lock the browser to that page (on iPad, Guided Access keeps customers from navigating away).
* **Download PNG** or **Printable PDF** — for a Static QR you want to print on a poster or sticker.
Open the **Setup guide** (the button on the **Check-in** settings page) for device recommendations, iPad Guided Access steps, brightness and mounting tips, and printing guidance.
Set the check-in window [#set-the-check-in-window]
**Check-in window** controls how many minutes before a booking starts a customer can check in. The window always closes when the booking ends. The default is **180** minutes (three hours). Change it on the **Check-in** settings page — enter a number of minutes and it saves when you click away.
For self check-in this is a hard limit — a customer can't check themselves in before the window opens. At the front desk it only governs the automatic behavior: staff can always check an early arrival in by hand.
Decide whether payment is required [#decide-whether-payment-is-required]
**Require payment before check-in** is a switch on the **Check-in** settings page:
* **On** *(Recommended)* — self check-in refuses to check in customers with unpaid orders, including unpaid court fees on OpenGame bookings. A customer with a fee sees **Pay to Check In** and pays inline before they're checked in.
* **Off** — an unpaid booking still checks in. Turn this off only if you collect payment at the front desk.
The same switch shapes the front desk: when it's on, scanning a customer with an unpaid fee opens the **Scan result** as **Needs attention** with the amount due (instead of checking them in automatically), so you collect before they go through. Staff can still check them in by hand either way.
What the customer experiences [#what-the-customer-experiences]
When a customer scans your posted QR, their phone opens a page titled **Check in at \[your club]**:
* If they're signed out, they see **Sign in to check in** (or **Create an account** for a first visit).
* Their eligible bookings appear under **Your bookings**, each with a **Check in** button. One tap checks them in.
* If a booking has an unpaid fee and payment is required, the button becomes **Pay to Check In** and they pay inline.
* If your club's waiver isn't signed, they're prompted with **Sign waiver** before they can check in.
* Walk-ins with no booking in their name can browse **Happening at \[your club]** to claim a guest spot booked under their name or join an open event on the spot.
Every self check-in shows up in the **Check-in** panel on your **Today** page under **Recently checked in**, badged **Self check-in**.
If something goes wrong [#if-something-goes-wrong]
* **A customer says the QR won't scan** — for a Dynamic QR, an old screenshot has expired by design; they need to scan the live tablet. Confirm the QR code is **Enabled** and the tablet is showing the current code.
* **"QR code expired"** on the customer's phone — the Dynamic code rotated between the scan and the tap. Ask them to scan the live display again.
* **A customer's booking doesn't appear** — they may have booked under a different email (they can sign out and back in), or the booking is outside the check-in window. A customer can't self-check-in before the window opens — if they're early and need to be in, the front desk can check them in by hand.
* **A paid customer is still asked to pay** — confirm the order is actually settled; unpaid court fees on OpenGame bookings count. If payment is collected at the desk, turn **Require payment before check-in** off.
* **The QR type is greyed out** — you're editing the built-in default QR, where the type is locked. Add a new QR code to pick a different type.
Related [#related]
* [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in)
* [Check-in reasons and troubleshooting](/help/facility-operators/check-in/check-in-reasons-and-troubleshooting)
* [Check-In & QR Scanner overview](/help/facility-operators/check-in)
# Set up the QR scanner at your front desk
Plug in a QR scanner and verify it with OpenCourt's built-in **Scanner test** so scanning a customer's Check-In QR Code checks them in from any admin page. *(About 3 minutes. You need a USB or Bluetooth 2D scanner and the admin panel open.)*
There is no scanner configuration to do in OpenCourt. Any USB or Bluetooth scanner that reads QR codes (a "2D imager") and connects as a keyboard works — including scanners that send an Enter, a Tab, or nothing at all after each scan. All suffix settings work.
Before you begin [#before-you-begin]
* A 2D (QR-capable) scanner. Any model works — most cost 20–40 USD. See [Choose a QR scanner for your front desk](/help/facility-operators/check-in/choose-a-qr-scanner).
* The scanner plugged into (or paired with) the computer that runs the admin panel.
* The admin panel open and signed in to the right club (check the club name in the top bar).
How the scanner works [#how-the-scanner-works]
The scanner acts like a keyboard: when it reads a code, it types the characters very fast. OpenCourt listens for that fast keystroke burst on every admin page and opens the **Scan result** the moment a scan finishes — you never click into a field first. It works whether or not your scanner is set to press Enter after each scan.
Set up and test the scanner [#set-up-and-test-the-scanner]
1. Plug the scanner into a USB port (or pair it over Bluetooth). Most scanners need no driver — the computer recognizes it as a keyboard.
2. In the admin panel, go to **Settings → Check-in** and click **Test your scanner** (in the **Front-desk QR scanning** card). The **Scanner test** page opens.
3. Point your scanner at the on-screen **QR code (2D)** and pull the trigger. The page reads **Waiting for a scan…** until keystrokes arrive.
4. Read the verdict. **Scanner working** means you are done — the scanner read every character correctly and works with check-in as-is.
5. To confirm the result wasn't luck, click **Test again** and scan once more. Then scan a customer's Check-In QR Code from any admin page — the **Scan result** appears.
A hands-free scanner stand is worth it if you check a line of customers in — set the scanner on the stand and customers hold their phone up to it. It is not required; a handheld scanner works the same way.
If the test reports a problem [#if-the-test-reports-a-problem]
Each verdict on the **Scanner test** page names the likely cause and the fix. In order of how often we see them:
* **No input received** — no keystrokes reached the page. Confirm the scanner is plugged in (or paired) and beeps on the trigger, and that the browser tab was focused. If it beeps but nothing arrives, the scanner is in serial (COM) mode instead of keyboard (HID) mode — scan the "USB keyboard" or "HID keyboard" configuration barcode in its manual (see [Configuration barcodes](#configuration-barcodes-how-scanner-settings-actually-change) below), then test again. If the scanner reads other codes elsewhere but never beeps on the QR code, it is a 1D (laser) model that cannot read QR codes — front-desk check-in needs a 2D imager. This is a hardware limit no setting fixes; see [Choose a QR scanner](/help/facility-operators/check-in/choose-a-qr-scanner) for 2D models.
* **Scanner working — that wasn't the test code** — the scanner read a QR code cleanly, but not the one on the test page (usually a real customer's code was scanned by accident). The scanner works with check-in; scan the test QR code above to finish the test.
* **Characters came through garbled** — keystrokes arrived but decode to the wrong characters. The scanner's keyboard-country setting doesn't match: scan the configuration barcode in its manual that sets the **US keyboard layout**, then test again.
* **Scanner too slow** — the code arrived correctly but with pauses between characters, so real check-in scans may be missed. Usual causes: a Bluetooth connection in low-power mode, or a configured keystroke delay. Connect by USB if you can, or scan the configuration barcode that sets the keystroke/character delay to zero.
* **Only part of the code came through** — a weak read. Raise the screen brightness, clean the scanner window, hold the scanner steady, and test again.
Configuration barcodes (how scanner settings actually change) [#configuration-barcodes-how-scanner-settings-actually-change]
Scanners have no settings app. You change a scanner's behavior by **scanning a special configuration barcode** printed in its manual or on the setup card in the box — the scanner beeps to confirm. Those barcodes are **specific to your scanner's brand and model**; there is no universal one, so use your own manual. If you've lost it, the manufacturer's site has it:
* Tera — [tera-digital.com](https://tera-digital.com)
* ScanAvenger — [scanavenger.com](https://scanavenger.com)
* Zebra — [zebra.com](https://www.zebra.com) (under Support)
* NetumScan — [netumscan.com](https://www.netumscan.com)
Every manual also includes a **"restore factory defaults"** barcode that undoes any change — a safe first step if a scanner behaves strangely and you don't know what was changed.
When to contact support [#when-to-contact-support]
If the test keeps failing after the fix above (or the verdict doesn't match what you see), send us:
1. On the verdict card, click **Show raw keystrokes** and screenshot the table that opens — it shows exactly what your scanner sent, key by key, with timing.
2. Your scanner's brand and model.
With that screenshot we can usually name the exact configuration barcode you need.
Related [#related]
* [Choose a QR scanner for your front desk](/help/facility-operators/check-in/choose-a-qr-scanner)
* [Check a customer in with the QR scanner](/help/facility-operators/check-in/check-a-customer-in)
* [Check-in reasons and troubleshooting](/help/facility-operators/check-in/check-in-reasons-and-troubleshooting)
* [Check-In & QR Scanner overview](/help/facility-operators/check-in)
# Assigning Coaches to Events
How to Assign Coaches [#how-to-assign-coaches]
1. Create or edit an event in the admin panel
2. In the **General** tab, find the **Coaches** section
3. Click the coach selector and search by name
4. Select one or more coaches — they appear as chips in the field
5. Save the event
Coaches are notified when they're assigned to a new event.
For Programs (Event Series) [#for-programs-event-series]
When editing a program (recurring event series), coaches assigned in the General tab apply to the entire series.
How It Appears to Members [#how-it-appears-to-members]
When coaches are assigned to an event, their names appear in the event details so members know who's teaching before they join.
Unified Coach Schedule [#unified-coach-schedule]
Assigned events appear in the coach's agenda alongside their private lessons. Whether a coach checks their schedule through **My Profile → Coach Schedule** or an admin views the **Agenda** tab, everything is in one place:
* Private and group lessons
* Assigned events (clinics, classes, etc.)
Coaches can also check their students in right there.
# Coach Booking Overview
The Coach Booking feature brings coaching into your club's digital experience. Instead of managing lessons through text messages, phone calls, or paper sign-up sheets, everything happens in one place — scheduling, booking, payments, and communication.
There are two sides to this feature:
1. **Private & Group Lessons** — Coaches set their availability, define lesson types and pricing, and members book directly through the app. The system handles court assignment and payment automatically.
2. **Coach Assignment to Events** — Admins assign coaches to clinics, group classes, camps, and other events so members know who's teaching.
Why it matters [#why-it-matters]
**For clubs:**
* Coaching becomes a managed, trackable revenue stream instead of an informal side arrangement
* Admins have full visibility into coach schedules, lesson history, and payment status
* Court assignment is automatic — no manual coordination needed
* Role-based pricing lets you offer member discounts on lessons without extra admin work
**For coaches:**
* A single schedule view shows everything — private lessons, group lessons, and assigned clinics
* If a coach already has an OpenCourt account, it can be linked to their coach profile, giving them access to their full schedule through the app
* No back-and-forth to coordinate court availability or collect payment — the system handles it
* Coaches can set their availability and let members self-book within those hours
**For members:**
* Browse coaches, see their profiles, qualifications, and availability
* Book lessons in a few taps — pick a coach, pick a service, pick a time, and pay
* Everything shows up in My Reservations alongside regular court bookings
* For group or semi-private lessons, members can invite others and split the cost
# Coach's Own Schedule View
When a coach has a linked user account, they can view their own schedule at **My Profile → Coach Schedule**. This is a unified view showing:
* All their upcoming private and group lessons
* All events (clinics, classes) they're assigned to
* Lessons appear in **purple**, assigned events in **blue**
This gives coaches a complete picture of their schedule without needing admin access.
They can change their schedule right there clicking “Manage Availability” button on the top right.
Coach can also check people in when they open a card with a lesson or a clinic.
# Creating a Coach Profile
Enabling Coach Booking [#enabling-coach-booking]
Before members can book lessons, enable the feature at the club level.
1. Go to **Settings → Coach Lessons**
2. Toggle **Enable Coach Booking** on
3. Configure club-wide defaults:
* **Default booking horizon** — How far in advance members can book (e.g., 30 days)
* **Minimum advance booking** — How soon before a lesson it can be booked (e.g., must book at least 24 hours ahead)
* **Default payment mode** — Whether lessons require payment at booking (**Immediate**) or can be paid later (**Deferred**)
* **Court restrictions** — Which courts can be used for lessons and in what priority order
These are defaults — each coach can override them individually from their own settings.
Creating a Coach Profile [#creating-a-coach-profile]
1. Go to **Coaches** in the admin sidebar
2. Click **Add Coach**
3. Fill in the coach's basic information:
* **First name** and **Last name** (required)
* **Title** (optional) — Shown under their name, e.g., "Head Pro", "Pickleball Coach"
4. **Link to a user account** (optional but recommended) — Use the **Link Profile** field to search for and select an existing OpenCourt user. This links the coach profile to their user account, which gives the coach access to their own schedule view in the app (at **My Profile → Coach Schedule**). The linked account does not need to match the coach's contact email — they are separate.
5. Fill in contact details:
* **Phone** — Displayed on the coach's public profile, so members can call or text. This is a contact number for the coach's profile and does not have to match the linked user account.
* **Email** — Same idea — a contact email for the coach's public profile, independent from the linked user account's email.
6. Add a **Profile photo** — Shown on the coaches page and the coach's detail page.
7. Write a **Bio** — A description of the coach's background, playing experience, teaching style, certifications, etc. Supports rich text formatting.
8. Save the profile.
Linking to a user account vs. contact details [#linking-to-a-user-account-vs-contact-details]
These serve different purposes:
| | FieldPurpose |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Link Profile** (user account) | Gives the coach access to their schedule in the app. The coach logs into their own OpenCourt account and sees their lessons and assigned events at **My Profile → Coach Schedule**. |
| **Phone** and **Email** on the profile | Displayed publicly on the coach's page so members can reach out. These are purely informational and do not need to match the linked account. |
A coach can function without a linked user account — they just won't have self-service access to their schedule. Admins can always manage everything from the admin panel.
# How Members Book a Lesson
Step 1: Browse Coaches [#step-1-browse-coaches]
Members visit the **Coaches** page on your club's site. They see coach cards with photos, names, and titles. They can click **Details** to learn more, or **Book** to go straight to booking.
Step 2: Coach Profile & Service Selection [#step-2-coach-profile--service-selection]
On the coach's detail page, members see the full profile — bio, contact information, availability, and a list of available services with pricing. The price shown is already adjusted for the member's role.
The member selects a service to start the booking flow.
Step 3: Pick a Date [#step-3-pick-a-date]
A calendar view shows available dates within the booking horizon. Dates with no availability are grayed out. The system checks both coach availability and court availability — a date is only shown as available if at least one bookable time slot exists.
Step 4: Pick a Time [#step-4-pick-a-time]
Available time slots for the selected date are listed. Only times where the coach is free AND a court is available appear. The member taps to select.
Step 5: Add Participants (Group/Semi-Private Only) [#step-5-add-participants-groupsemi-private-only]
For services with max participants greater than 1, the member can add other players:
* Enter guest names directly and pay for everyone, or
* Share an invite link so other players can join and pay for themselves
The booking member is always participant #1.
Step 6: Confirm & Pay [#step-6-confirm--pay]
The member reviews the booking summary (coach, service, date, time, price) and confirms.
* **Immediate payment** — Taken to a checkout screen. The lesson is created after payment succeeds.
* **Deferred payment** — The lesson is booked immediately and appears in My Reservations. Payment is collected later.
* If a user has a booking pass for a private lesson they can use it to book this lesson.
After booking, the member is redirected to **My Reservations** where their lesson appears alongside their other bookings.
# Coach Booking
Coach Booking brings private lessons, group classes and clinics into your club's schedule. Set up coach profiles, lesson types and court rules, then see how members book and how you manage lessons.
Articles [#articles]
* [Coach Booking Overview](/help/facility-operators/coaches/coach-booking-overview) — The Coach Booking feature brings coaching into your club's digital experience.
* [Creating a Coach Profile](/help/facility-operators/coaches/creating-a-coach-profile) — Learn how to activate Coach Booking at the club level and configure default settings like booking windows, payment modes, and court restrictions.
* [Setting Up Private & Group Lessons](/help/facility-operators/coaches/setting-up-private-and-group-lessons) — Learn how to configure a coach’s availability, create lesson types, and control pricing.
* [Setting up Court Restrictions & Priority](/help/facility-operators/coaches/setting-up-court-restrictions-and-priority) — By default, the system auto-assigns any available court for a lesson.
* [How Members Book a Lesson](/help/facility-operators/coaches/how-members-book-a-lesson) — See the full booking experience from the member’s perspective — from browsing coach profiles and selecting a service to choosing a date, adding participants, and completing payment.
* [Managing Lessons as an Admin](/help/facility-operators/coaches/managing-lessons-as-an-admin) — Learn how to use the Coach Agenda to view and manage all booked lessons and assigned events in one place.
* [Assigning Coaches to Events](/help/facility-operators/coaches/assigning-coaches-to-events) — Beyond private lessons, you can assign coaches to any event — clinics, group classes, drills, camps, or any other event type.
* [Coach's Own Schedule View](/help/facility-operators/coaches/coachs-own-schedule-view) — When a coach has a linked user account, they can view their own schedule at My Profile → Coach Schedule.
# Managing Lessons as an Admin
Coach Agenda [#coach-agenda]
The **Agenda** tab on each coach's page gives admins a chronological view of all booked lessons and assigned events.
1. Go to **Coaches → \[Coach Name] → Agenda** tab
2. View upcoming lessons grouped by date — each showing time, court, participants, and payment status
3. Click a lesson to open details, check in participants, or manage payments
Payment Status [#payment-status]
Each lesson shows its payment status:
* **Paid** — Payment collected (immediate mode) or manually marked as paid
* **Pending** — Awaiting payment (deferred mode)
* **Cancelled** / **Refunded**
For deferred payment lessons, admins can collect payment through the event participants UI.
# Setting up Court Restrictions & Priority
Club-Level (All Coaches) [#club-level-all-coaches]
In **Settings → Coach Lessons**, configure:
* **Allowed courts** — Only these courts will be used for lessons
* **Priority order** — When multiple courts are available, the highest-priority one is assigned first
Per-Coach Override [#per-coach-override]
1. Go to **Coaches → \[Coach Name] → Settings** tab
2. Toggle **Override Club Court Settings**
3. Select which courts this specific coach can use
4. Drag to set the priority order
This is useful for dedicating specific courts to specific coaches, or allowing a coach to use a hidden "teaching court" that doesn't appear on the public schedule.
# Setting Up Private & Group Lessons
Setting Up the Coach's Schedule [#setting-up-the-coachs-schedule]
Each coach has a **weekly schedule template** that defines when they're available for lessons, plus **date exceptions** for one-off changes like holidays or vacation days.
Weekly Schedule [#weekly-schedule]
1. Go to **Coaches → \[Coach Name] → Schedule** tab
2. For each day of the week, add time blocks when the coach is available
* Example: Monday 9:00 AM – 12:00 PM and 2:00 PM – 6:00 PM
* Multiple blocks per day are supported (e.g., morning and afternoon with a lunch break)
3. Leave a day empty if the coach doesn't work that day
Members can only book during these availability windows. The system automatically combines the coach's schedule with court availability — a time slot only appears as bookable if both the coach and a court are free.
Date Exceptions [#date-exceptions]
For holidays, vacations, or one-off schedule changes:
1. On the **Schedule** tab, select a specific date
2. Either:
* Mark the coach as **unavailable** for that entire day, or
* Set **custom hours** that override the weekly template for that date
Date exceptions take priority over the weekly schedule for that specific date.
Admins can easily preview the coach’s schedule:
***
Creating Services (Lesson Types) [#creating-services-lesson-types]
Services define what a coach offers — the type of lesson, how long it is, how much it costs, and how many people can join.
1. Go to **Coaches → \[Coach Name] → Services** tab
2. Click **Add Service**
3. Configure the service:
* **Name** — A clear name members will see, e.g., "1-Hour Private Lesson", "1-Hour Semi-Private (2 Players)", "1-Hour Group Lesson (Up to 4)"
* **Description** (optional) — Additional details shown to members during booking
* **Duration** — Lesson length in minutes (e.g., 60, 90, 120)
* **Price** — The price per person (more on this below)
* **Max participants** — This is the key field that determines the lesson type (see below)
* **Payment mode** — **Immediate** (pay at booking) or **Deferred** (book now, pay later)
4. Drag services to reorder them — this is the order members see when booking
How Max Participants Works [#how-max-participants-works]
The **max participants** setting controls the entire lesson dynamic:
**Private lesson (max participants = 1)**
* Only one person books this slot. Once booked, the time slot is taken — no one else can join.
* The price shown is the total price for the lesson.
* Straightforward: one member, one coach, one court.
**Semi-private or group lesson (max participants = 2, 3, 4, etc.)**
* The member who books first can add additional people up to the max.
* **The price is per person.** If a semi-private lesson is $50/person and the member adds a second player, the total is $100.
* The booking member can add participants in two ways:
1. **Add them directly** — Enter names during the booking flow and pay for everyone
2. **Share an invite link** — Send a link to other players so they can join and pay for themselves
Role-Based Pricing (Member Discounts) [#role-based-pricing-member-discounts]
You can set different prices for different membership roles:
1. When editing a service, expand the **Member Pricing** section.
2. Add custom prices for specific roles (e.g., Gold Members pay $50/person instead of the default $70/person - price for non-members).
3. Members whose role doesn't have a custom price pay the default.
# Community Groups & Chats
What You Can Do with Community [#what-you-can-do-with-community]
* **Create Groups:** e.g. for players by skill level, interest, or event (e.g., *Beginners Chat*, *Early Birds*, *Tournament Players*).
* **Public or Private:**
* *Public groups* are visible to all members and non-members, and anyone can join.
* *Private groups* require an invitation code to join.
* **Communicate Easily:** Post updates about open spots, new clinics, or event changes.
* **Coordinate Play:** Players can share event links directly in the chat (like “Join me for this open play!”) so others can quickly sign up.
* **Build Community:** Members can chat, share photos, and plan games together — just like in popular messaging apps.
Players Experience [#players-experience]
* Players see the **Community block** on the app home page and can explore groups there.
* They can browse and join public groups
* Or, if it’s a private group, they can join if someone invites them and sends them the code of this group.
* Inside a group, members can:
* Send messages, tag others, and get notifications.
* Share event links so others can join quickly.
* See who else is in the group and manage their own settings (mute, leave, etc.).
***
Example Groups You Might Create [#example-groups-you-might-create]
* **Beginners Chat** – updates for new players learning the game.
* **Early Birds** – for members who like to play before work.
* **Tournament Players** – restricted to participants of a specific tournament.
***
✅ The Community feature gives your club a built-in way to **connect players, keep them engaged, and make scheduling games easier than ever.**
# Creating groups / chats
Creating a Group. [#creating-a-group]
1. Go to the **Community** tab in the left-hand menu in the Admin panel.
2. Click **Create Group**.
3. Enter a **Group Name** (e.g., *Beginners Chat* or *Early Birds*).
4. Add a description.
5. Choose whether it’s **Public** (visible to everyone on the Home Page and at the Community tab) or **Private** (join only by invitation code).
6. Click **Create**.
Once created, you can:
* See the group in your list.
* Edit or delete it anytime.
* Share the group code or invitation link with players.
* Add members manually from your club’s participant list.
Featuring on the Home Page [#featuring-on-the-home-page]
You can feature groups on the Home Page so members can easily discover and join them. To enable this, go to Settings → Club Home Settings. At the bottom of the page, find Public Groups Visibility and toggle it on. This will display the groups block on your Home Page.
Check out what your players will see and how they can use the Community feature [here](/help/facility-operators/community/community-groups-and-chats#xyrw3rmi8qs).
# Community
Community groups and chats keep your players connected between visits.
Articles [#articles]
* [Community Groups & Chats](/help/facility-operators/community/community-groups-and-chats) — The Community feature makes it easy for clubs to build stronger connections with their players.
* [Creating groups / chats](/help/facility-operators/community/creating-groups-chats) — The Community feature helps you keep your players engaged and connected.
# Blocking Off Courts or Marking Time as Unavailable
When to Use It [#when-to-use-it]
Use this feature when you want to:
* Reserve a court for **maintenance or repairs**.
* Block time for **internal meetings or staff use**.
* Prevent bookings during **special events or holidays**.
* Keep certain time slots **off-limits** without showing event details.
***
How to Mark a Court as Unavailable [#how-to-mark-a-court-as-unavailable]
1. Go to the **Schedule** page.
2. Click on the time slot you want to block.
3. Choose the **“Unavailable”** option.
4. (Optional) Add a short note (e.g., *Maintenance*, *Reserved for Club Use*).
5. Click **Save**.
***
What Players See [#what-players-see]
* The blocked time appears **grayed out** on the schedule.
* Players **cannot book or view details** for that time.
* If you added a note (like *Maintenance*), they’ll see that label.
***
✅ That’s it! The court will stay unavailable for the selected time — keeping your schedule organized and avoiding accidental bookings.
# Creating a reservation
In a vast majority cases, your customers will be making their own court reservations. However, sometimes you need to create a reservation for them (for example, when you're processing a walk-in).
Admins can add reservations for any customer in just a few taps. Below you’ll find two equally quick methods. Choose the one that fits your day‑to‑day routine.
If it's an existing customer with an account on OpenCourt, see instructions below. If it's a new customer, then add them to the platform first.
Method 1: Create from the Schedule Page [#method-1-create-from-the-schedule-page]
1. In the left-hand admin menu, click the **Schedule** page to open the schedule grid.
2. Click an empty time slot you'd like to reserve. A **New Booking** pop-up window will appear.
3. In the pop-up window, choose the duration, select **Reservation** and click **Continue**.
4. The "Create New Reservation" page will open with the time slot prefilled. Search for the player to assign a host for this reservation.
* Use the dropdown to find the customer by name or email.
* If the customer hasn't been created yet and has never interacted with the platform, you won't find them here. First, you'll need to [add new customer](/help/facility-operators/customers-and-families/adding-a-new-customer) to your club.
* You only add the host here. You can add more participants later on after the reservation is created.
5. Choose the reservation settings
* **Open Game:** allowing anyone who spots this reservation on the schedule to join until all slots are filled.
* **Private:** player's name won't be seen in the reservation publicly
6. Double-check court, date, time, and duration — then hit **Create Reservation**. You're done! The **Reservation Info** pop-up window will show up after the reservation is created.
When the reservation is created by the admin and not by the customer, no notification email is dispatched to the customer. Please make sure the customer is aware you've created the reservation for them.
Method 2: Create from the Reservations Page [#method-2-create-from-the-reservations-page]
1. In the left-hand menu, click the **Reservations** page, then hit **New Reservation**.
2. The "Create New Reservation" page will open **without** the time slot prefilled. Search for the player to assign a host for this reservation.
* Use the dropdown to find the customer by name or email.
* If the customer hasn't been created yet and has never interacted with the platform, you won't find them here. First, you'll need to [add new customer](/help/facility-operators/customers-and-families/adding-a-new-customer) to your club.
* You only add the host here. You can add more participants later on after the reservation is created.
3. Choose the reservation settings
* **Open Game:** allowing anyone who spots this reservation on the schedule to join until all slots are filled.
* **Private:** player's name won't be seen in the reservation publicly
4. Scroll down and click on " + **Add a Time Slot**"
* Set **Date, Time, Court, and Duration**.
* You can see where the reservation fits in the schedule in the preview window below.
5. Click **Create Reservation.** You're done! The **Reservation Info** pop-up window will show up after the reservation is created.
# Dependent Spaces
***
Who Can Configure This [#who-can-configure-this]
Dependent Spaces rules can be created and managed by both club admins and Super Admins.
***
How to Add a Rule [#how-to-add-a-rule]
1. Go to Settings → Spaces and Categories.
2. Scroll down to the Dependent Spaces section.
3. Click + Add rule.
4. In the Primary space dropdown, select the space that, when booked, should block the others.
5. Under Blocks these spaces, check every space that should be blocked when the primary is booked.
6. Review the Preview at the bottom of the modal to confirm the logic looks correct.
7. Click Add rule to save.
***
How the Rule Works [#how-the-rule-works]
Dependent Spaces rules are bidirectional. You don't need to create a second rule in reverse — OpenCourt applies blocking both ways automatically.
Example: Primary space = Court 1 (Tennis). Blocks = Court 2 (Pickleball) and Court 3 (Pickleball). → When Court 1 (Tennis) is booked, Court 2 and Court 3 are both blocked off. → When Court 2 or Court 3 is booked, Court 1 is blocked off. → If an event or program is created on Court 1, Court 2 and Court 3 are blocked for that time window too.
***
What the User Sees [#what-the-user-sees]
When a dependent space is blocked, it appears greyed out with a striped pattern on the schedule — users won’t see a booking option for that time slot. No error message is shown; the space simply looks unavailable, the same way an already-booked court appears.
In the example below, Court 1 is reserved and Courts 2 and 3 are automatically blocked off for the same time window.
Editing or Deleting a Rule [#editing-or-deleting-a-rule]
Each rule in the Dependent Spaces list has an edit (pencil) and delete (trash) icon. Click the pencil to update which spaces are linked, or the trash icon to remove the rule entirely.
***
💡 Tip: The primary space won't appear in the "Blocks these spaces" checkbox list — only the other spaces are shown. This prevents you from accidentally creating a self-referencing rule.
# Court Bookings
Everything about the courts, bays and other spaces themselves: how your schedule is built, how a reservation is made and changed, and how you take a space out of circulation.
Events and programs are a separate thing with their own rules — see [Events & Programs](/help/facility-operators/events-and-programs). If you are not sure which you need, start with [Reservations vs. Events](/help/facility-operators/court-bookings/reservations-vs-events).
Start here [#start-here]
* [Introduction to Court Scheduling](/help/facility-operators/court-bookings/introduction-to-court-scheduling) — how the schedule is put together.
* [Reservations vs. Events](/help/facility-operators/court-bookings/reservations-vs-events) — the difference, and when to use each.
* [Creating a reservation](/help/facility-operators/court-bookings/creating-a-reservation) — book a space for a customer from the admin side.
Shape your schedule [#shape-your-schedule]
* [Schedule Configuration Customizations](/help/facility-operators/court-bookings/schedule-configuration-customizations) — how the schedule looks and behaves for your club.
* [Blocking Off Courts or Marking Time as Unavailable](/help/facility-operators/court-bookings/blocking-off-courts-or-marking-time-as-unavailable) — maintenance, private hire, weather.
* [Dependent Spaces](/help/facility-operators/court-bookings/dependent-spaces) — when booking one space has to take another out of circulation.
Beyond courts [#beyond-courts]
* [Resources (Ball Machines, Equipment & More)](/help/facility-operators/court-bookings/resources-ball-machines-equipment-and-more) — bookable things that are not a court.
Related [#related]
* [Events & Programs](/help/facility-operators/events-and-programs) — leagues, clinics, open play and everything else on the schedule.
* [Pricing & Discounts](/help/facility-operators/pricing-and-discounts) — what a booking costs, and how to discount it.
# Introduction to Court Scheduling
Schedule page is refreshed every 30 seconds so that you always see the up-to-date version of your court schedule.
You will see the Reservations and Events on your **Schedule** page, as well as on the dedicated **Reservations** and **Events & Programs** pages.
# Reservations vs. Events
Both Reservations and Events block time on one or more courts, but they differ in who creates them, how players join, and how pricing works. They both show up on the **Schedule** tab.
Reservations [#reservations]
* **Who creates them:** Players (or admins on their behalf).
* **Purpose:** Book a specific court and time for a private game.
* **Pricing:** Uses your club’s standard court-booking rates.
* **Player flow:** The person booking (host) can invite other players to fill the spots.
* **Open Game option:** The host can mark the reservation as **Open Game**, allowing anyone who spots it on the schedule to join until all slots are filled.
Events [#events]
* **Who creates them:** Club staff.
* **Purpose:** Offer organized play – open plays, clinics tournament, leagues, socials, etc.
* **Pricing:** Set per event, with optional member/non-member pricing tiers.
* **Formats** are manageable via time slots that you define for the event.
* **One-off:** A single date, one or multiple courts and/or one or multiple time slots.
* **Multi-day:** A single sign-up covers several days (e.g., a league that repeats every Wednesday; users sign up once but are on the list for each time slot). Created by defining time slots on different days within one single event.
* **Recurring series:** Players register for each date independently within the series. [Learn how to create an event series](/help/facility-operators/events-and-programs/creating-recurring-event-series).
* **Alias:** You’ll sometimes see “Program” used interchangeably with Event.
In short, **Reservations** are player-driven court bookings, while **Events** are club-run sessions that players can join.
# Resources (Ball Machines, Equipment & More)
Overview [#overview]
Here's how the feature works end to end:
1. **Admin creates resources** — e.g., "Ball Machine 1", "Ball Machine 2"
2. **Admin sets up resources as booking add-ons** — configures pricing, courts where this resource can be booked, and who can book
3. **Member books a court** — during the booking flow, they see available resources and can add one to their reservation
4. **System handles the rest** — resource availability is tracked, pricing is added to the checkout, and the resource is reserved for the same time slot as the court
***
Setting Up Resources [#setting-up-resources]
Step 1: Create Resources [#step-1-create-resources]
1. Go to **Resources** in the admin sidebar
2. Click **Add Resource**
3. Enter the resource name (e.g., "Ball Machine 1")
4. Toggle **Enabled** on
5. Save
If you have multiple units of the same resource (e.g., three ball machines), create each one as a separate resource. You can batch-create them — for example, creating "Ball Machine" with a quantity of 3 produces "Ball Machine 1", "Ball Machine 2", and "Ball Machine 3".
Step 2: Configure as Booking Add-Ons [#step-2-configure-as-booking-add-ons]
Creating a resource makes it exist in the system, but members won't see it during booking until you set it up as a **booking add-on**.
1. Go to **Settings → Booking Upsells**
2. Navigate to the **Resources** section
3. Click to add a resource as a booking add-on
4. Configure:
* **Price** — The amount to charge (can be left empty for free resources) for every membership tier and non-members
* **Pricing mode** — **Fixed** (flat fee regardless of booking duration) or **Per Hour** (price scales with the length of the court booking)
* **Courts** — Which courts this resource is available on (all courts by default, or restrict to specific ones)
5. Save
Pricing Examples [#pricing-examples]
| | Member books 1-hour court | Member books 2-hour court |
| ------------------------------------- | ------------------------- | ------------------------- |
| Ball Machine — **Fixed** at $15 | Court fee + $15 | Court fee + $15 |
| Ball Machine — **Per Hour** at $10/hr | Court fee + $10 | Court fee + $20 |
Role-Based Pricing (Advanced) [#role-based-pricing-advanced]
For more granular control, you can set different prices for different membership roles. This is configured in the club settings and supports:
* **Default price** for all users
* **Non-member price** (different rate for non-members)
* **Per-role pricing** (e.g., Gold members pay $10, Silver members pay $12, non-members pay $15)
* **Time-based pricing** (e.g., weekend premium, off-peak discounts)
Court Restrictions [#court-restrictions]
By default, a resource add-on is available on all courts. If a resource is physically located at a specific court or only makes sense on certain courts, restrict it:
1. Edit the resource add-on
2. In the **Courts** section, select which courts this resource is available on
3. Members booking a court outside this list won't see the resource as an option
Role-Based Availability [#role-based-availability]
You can control which users see and can book each resource based on their membership role:
* **Non-authenticated users** — Can they see the resource?
* **Non-members** — Can they book it?
* **Specific membership roles** — Toggle on/off per role
***
How Members Book Resources [#how-members-book-resources]
During Court Reservation [#during-court-reservation]
When a member books a court, they go through the reservation flow. If resources are configured as booking add-ons, a **Services** step appears:
1. Member selects a court and time
2. On the **Services** step, available resources are shown with:
* Resource name (e.g., "Ball Machine 1")
* Price (adjusted for the member's role and booking duration)
* Availability status — if the resource is already booked for that time slot, it's shown as unavailable
3. Member checks the box next to the resource to add it
4. The total price updates to include the resource fee
5. Member completes checkout — the resource is reserved for the same time slot as the court
Availability [#availability]
The system automatically tracks resource availability:
* Each resource instance can only be booked once per time slot
* If "Ball Machine 1" is taken but "Ball Machine 2" is free, the member sees one available and one unavailable
* When editing an existing reservation, the member's current resource booking is excluded from conflict checks (so they can keep it without it showing as "taken")
***
Managing Resource Reservations (Admin) [#managing-resource-reservations-admin]
Resource Schedule [#resource-schedule]
Admins can view and manage resource reservations from the **Resources → Schedule** view. This shows a calendar of all resource bookings — both those made through court reservations and any standalone resource reservations created by admins.
From the schedule view, admins can:
* See which resources are booked and when
* Create resource reservations directly (e.g., to block off maintenance time)
* Edit or cancel existing resource reservations
Deleting Resources [#deleting-resources]
When deleting a resource, the system checks for future reservations. If the resource has upcoming bookings, you'll be warned before confirming the deletion. Deleting a resource is a soft delete — historical booking data is preserved.
***
Tips [#tips]
* **Name resources specifically** — Use "Titan One Ball Machine", "Sports Tutor Ball Machine" instead of just "Ball Machine" so members know exactly which unit they're getting
* **Use Fixed pricing for simple setups** — If the resource fee shouldn't change based on booking duration, Fixed pricing is simpler
* **Use Per Hour pricing for time-sensitive resources** — If longer bookings should cost more (e.g., renting a ball machine for 2 hours costs more than 1 hour), use Per Hour
* **Restrict to relevant courts** — If a ball machine can only be used on courts 1–3, set up the court restriction so members on court 4 don't see it as an option
* **Block maintenance time** — Use the admin schedule view to create resource reservations during maintenance windows so members can't book the resource during that time
# Schedule Configuration Customizations
What you can control [#what-you-can-control]
* **Daily hours:** Set a **Start Time** and **End Time** per day of the week.
* **Audience targeting:** Apply any specific schedule configuration to a specific **membership group**.
* **Booking availability:** per membership group, court booking can be enabled for the entire day from the **Start Time** to the **End Time**, or can cover only portions of it (for example, for a membership that only allows booking before 5pm).
* **Time segments (time slot length):**
* **Default:** 30 minutes.
* **Custom:** often 60 minutes or 90 minutes, but could be anything
* **Mixed day:** Combine segments (e.g., 90-minute blocks in the morning, 30-minute blocks later).
How to request schedule configuration change [#how-to-request-schedule-configuration-change]
Contact your OpenCourt representative to request changes, or email us at [club-support@getopencourt.com](mailto:club-support@getopencourt.com). Make sure to provide information on how you would like the schedule to be customized.
# Adding a new customer
Most of the time, new customers create an account on OpenCourt on their own within a minute by entering their email and their name.
But if someone calls the front desk or walks in wanting to reserve a court or join an Open Play or tournament, here’s how to add them to the platform.
Method 1 (Recommended) [#method-1-recommended]
Ask them to [scan QR code of your waiver](/help/facility-operators/waivers/signing-a-waiver-at-the-front-desk) and fill it out. Once they do it, they're automatically added to the system.
Method 2 (Manually) [#method-2-manually]
1. Head to the **Users** Tab
* Jump into your admin panel and click on the **Users** tab from the left-hand menu.
2. Click "**Add New Customer**" at the right top corner.
* Type in their email address. If they already have an account, it’ll pop up.
If not, it’ll create a new one for them. Fill out their name, and it's all set.
What you can do next [#what-you-can-do-next]
* [Sell them a membership or assign for free](/help/facility-operators/customers-and-families/selling-a-membership-to-customers)
* Book a court for them
* Add them to any event (Open Play, Tournament, Clinic etc)
* Sell them products via POS
Quick Tip [#quick-tip]
Make sure they signed a waiver before their first game.
# Club Credit
Players can receive Club Credit in several ways:
* By redeeming a [gift card](/help/facility-operators/point-of-sale/sell-and-manage-gift-cards)
* By receiving a **refund** issued as club credit
* Or other types of credit, e.g. compensation, promo credit, gift from another member, etc.
***
For Admins: Managing Club Credit [#for-admins-managing-club-credit]
Adding or Adjusting a User’s Club Credit Balance [#adding-or-adjusting-a-users-club-credit-balance]
1. Go to the **User Profile** of the member or customer.
2. Open the **Club Credit** tab.
3. Choose the type of credit:
* **Promotional credit**
* **Compensation**
* **Cash payment**
* **Gift card**
* **Refund**
* **Correction**
* **Other**
4. Enter the amount to **add** or **deduct**.
5. (Optional) Add an internal note — for example: *“Gift card from Alice”*.
6. Click **Adjust Club Credit**.\
The new balance appears instantly.
Using Club Credit as an Admin [#using-club-credit-as-an-admin]
Whether they’re paying for a reservation, an event, or a POS purchase, you can apply their credits toward the full amount or a partial payment—whichever the customer prefers.
1. At checkout, under **Other tenders**, click **Use club credit** and enter the amount to apply.
2. Complete the payment. If the credit doesn't cover the total, charge the rest to a card.
The transaction receipt will show that the payment was made using Club credit.
***
For Users: Paying With Club Credit [#for-users-paying-with-club-credit]
Users can pay for reservations or events directly from their club credit balance.
Using Club Credit for a Booking [#using-club-credit-for-a-booking]
1. Start a court reservation or event sign-up.
2. At checkout, the user will see their available **Club Credit balance**.
3. They can apply club credit toward the purchase.
If the credit does **not cover the full amount**, users can:
* Use **mixed payment**, where part of the charge is paid by club credit and the remaining balance is charged to their card.
Example [#example]
* User has **$55** in club credit
* Booking total is **$90**
* User can apply $55 from club credit and pay the remaining $35 with their saved card
***
Viewing Club Credit History (User Side) [#viewing-club-credit-history-user-side]
Users can see all club credit activity under **My Profile → Club Credit**:
* Total credit received
* Source of credit (gift card, refund, admin adjustment)
* How much was used for each transaction
* Remaining balance
They can also view details in **Billing History**, where each transaction clearly shows:
* How much was paid using club credit
* How much (if any) was charged to their card
***
Club Credit offers a flexible and transparent way for players to manage their spending at the club — and give admins a clear way to issue refunds, gift cards, or promotional balances. If your club issues or accepts club credit, this feature ensures a smooth experience on both ends.
# Creating and managing a family account
Overview [#overview]
Members and admins can create a family and add family members in two ways:
* **Add Existing** — use this when the family member should have their own separate account. This is best for a spouse, partner, or another person who wants to manage their own account, make their own reservations, and join Open Play, events, lessons, or other activities on their own.
* **Create New** — use this for a child or dependent who does not need their own login or email and will not manage the account themselves.
Once family members are added, eligible family booking passes can be shared across the family.
How users can create a family [#how-users-can-create-a-family]
1. Open your profile.
2. Go to **My Family**.
3. Click **Create a Family**.
4. Click **Add Member**.
Option 1: Add an existing account [#option-1-add-an-existing-account]
Use **Add Existing** when the family member should have their **own separate account**.
This is best for:
* spouses or partners
* adults who want to make their own reservations
* adults who want to sign up for lessons or events on their own
To add an existing account:
1. Ask the family member to create their own account first - just enter and verify their email, and type their name - that’s it.
2. In **My Family**, click **Add Member**.
3. Choose **Add Existing**.
4. Search by their email address.
5. Select their account and add them to the family.
Option 2: Create a new dependent [#option-2-create-a-new-dependent]
Use **Create New** for children or dependents who do not need to manage an account themselves.
To create a new dependent:
1. In **My Family**, click **Add Member**.
2. Choose **Create New**.
3. Enter the child’s information, including date of birth.
4. Click **Add Member**.
How admins manage families and dependents [#how-admins-manage-families-and-dependents]
Family memberships are managed under one primary account holder. The primary member is the one who purchases and pays for the membership, while the dependent family members are included under that membership and receive the same membership benefits without paying separately.
For a couple membership, this usually means one primary member and one dependent. For a family membership, there can be one primary member and multiple dependents.
Only the primary account holder is billed for the membership, and if the primary member cancels it, all dependents connected to that family membership will lose their membership benefits as well.
Where to view families [#where-to-view-families]
To see all families that have been created:
1. Go to **Users**
2. Open **Families and Groups**
Any family created by a member will appear there.
How admins can create a family manually [#how-admins-can-create-a-family-manually]
Admins can also create a family on behalf of members.
1. Go to **Users**
2. Click **Create New Family**
3. Start typing the **primary member name** in the field
4. To add a family dependent member click “Add Member”
5. If it’s a member who wants to have their own account, make their own reservations etc, you should add a new user first with their email and name. Then click Add Existing
6. If their dependents don’t have their own accounts and won’t need it (e.g. kids who don’t have their emails and don’t need to manage their own reservations etc), then click Create new dependent.
7. Enter the user’s email, first name, and last name
Assign Dependent vs. just being in the family [#assign-dependent-vs-just-being-in-the-family]
This part is important:
If a member is only part of the family [#if-a-member-is-only-part-of-the-family]
They can use **shareable family booking passes** if the pass is configured that way.
If you click Assign Dependent [#if-you-click-assign-dependent]
They receive the **same benefits as the primary member**, not just shared passes.
This may include:
* the same pricing (e.g. free or discounted booking for members)
* the same booking window (e.g. they can book 14 days in advance)
* other membership-level benefits tied to the primary member
Such dependents are treated the same as the primary member and receive the same membership benefits, but they do not pay separately, since the primary member pays for the full couple or family membership.
Best practice [#best-practice]
Use **Assign Dependent** only for family members who should truly receive the same membership rights as the primary member. This is especially useful for couple-style memberships.
If a family includes more members, but only some should get full benefits, keep the others in the family without assigning full dependent benefits.
***
What happens after a family is created? [#what-happens-after-a-family-is-created]
Once a family is set up, family members can use eligible **family booking passes** that are shared with the family.
# Custom Fields in Memberships
How It Works [#how-it-works]
1. If you want to add the custom fields, please contact your OpenCourt representative.
2. Define what extra details members need to provide.
* Examples:
* Partner’s name + email (for Couple’s Memberships)
* Partner’s and children’s names + emails (for Family Memberships)
* Choose whether each field is **optional** or **required**.
3. **User Experience**
* When purchasing a membership, members will select a payment plan first.
* Below it, they’ll see the **custom fields** you’ve created in “Additional Information” block.
* Required fields must be completed before checkout.
4. **Where Admins See the Information**
* **Email Notifications**: If you’ve enabled membership notifications, you’ll receive an email with the new member’s details, including the custom fields.
* **Member Profile**: The same information will also appear on the **Membership tab** of the user’s profile in the admin dashboard.
***
Example [#example]
* A **Family Membership** requires:
* Partner’s name + email
* Children’s names
* When the primary account holder signs up, they’ll fill in those fields before completing checkout.
* The admin receives the details by email and can always access them later in the user’s profile.
***
Key Notes [#key-notes]
* You can add as many custom fields as needed.
* Each field can be set as **optional** or **required**.
* Collected data is always available in both **email notifications** and the **user profile**.
# Families & Group Memberships
***
How Family Memberships Work [#how-family-memberships-work]
* Each family or group has **one Primary Member**.
* The Primary Member:
* Holds the paid membership
* Is financially responsible for the plan
* **Dependent Members**:
* Do not pay individually
* Receive the same membership benefits as the Primary Member
* Automatically sync with the Primary Member’s membership status and dates
If the Primary Member’s membership:
* Is canceled or terminated → all dependents lose benefits at the same time
* Is resumed or reassigned → dependents can regain benefits accordingly (you
***
Creating a Family or Group [#creating-a-family-or-group]
1. Go to the **Users** section.
2. Open the **Families & Groups** tab.
3. Click **Create Family**.
4. Enter a **Family / Group Name** and click **Create**.
At this stage, the family exists but has no members assigned yet.
***
Assigning the Primary Member [#assigning-the-primary-member]
1. Inside the family, click **Add Member**.
2. Search for and select the user who will be the **Primary Member**.
3. Add them to the family.
⚠️ The Primary Member must have a **family/group membership plan** assigned for dependents to receive benefits.
***
Adding Dependent Members [#adding-dependent-members]
1. Click **Add Member** again.
2. Select another user.
3. Click **Assign Dependent**.
Once assigned:
* The dependent immediately inherits the Primary Member’s membership benefits
* Their membership expiration date matches the Primary Member’s
You can repeat this process to add multiple dependents.
***
Managing Family Members [#managing-family-members]
From the **Family view**, admins can:
* View all members in the family
* Remove a member from the family
* Open a member’s profile
From an individual **User Profile**, members will see a **Family** tab showing:
* Family / group name
* Their role (Primary or Dependent)
* Total number of members
* A **Detach from Family** option (admin-only)
Removing a member from the family immediately removes their dependent benefits.
***
Membership Sync Rules [#membership-sync-rules]
* Dependents always follow the **Primary Member’s membership status**
* If the Primary Member:
* Cancels or loses membership → dependents become non-members
* Changes membership → dependent benefits update accordingly
* Dependent membership expiration dates always match the Primary Member’s expiration date
***
When to Use Families & Groups [#when-to-use-families--groups]
* Family memberships (parents + children)
* Couples or household memberships
* Group or team-based memberships
* Any plan where one person pays and others share access
***
The Families & Group Memberships feature simplifies group-based billing and benefit management, ensuring everyone stays in sync with the Primary Member’s membership status.
# Family member types, rule sets & passes
How a family membership treats each person on it — who gets which rule set, who gets passes, the limits that apply, and what happens across the membership's lifecycle.
Who gets what [#who-gets-what]
| Who | Rule set | Booking passes |
| ----------------------- | -------------------------------------------------------------------------------------- | ------------------------------- |
| **Organizer** | the plan's own rule set | the plan's own passes |
| **Member on a type** | the type's rule set, or the plan's rule set if the type is set to *Same as membership* | the passes defined on that type |
| **Member with no type** | the plan's own rule set | none |
The organizer always keeps the plan's own rule set and passes — member types only affect the family members you attach.
Member types [#member-types]
* A **member type** (e.g. *Adult*, *Kid*) carries its own rule set and its own booking passes. Define them under **Family member types** on the plan.
* **Capacity** is per type: set how many people can hold a type, or leave it blank for unlimited.
* **Rule set** can be *Same as membership* (the member uses the plan's rule set) or any rule set you pick. The helper text reads *"What family members of this type can do at the club."*
* A plan with **no types** treats every family member the same: the plan's rule set, no per-person passes.
Booking passes on a type [#booking-passes-on-a-type]
* Passes on a type are granted to each member who holds that type, for the membership's **billing period**.
* **Scheduled allocation cadences are not available on types** — type passes follow the billing-period cadence only.
* **Two ways to share passes.** Passes on a member type give each member their own allocation. A pass template with **Can be redeemed by family members** switched on instead gives the whole family one shared pool, drawn from the organizer's allocation — see [Create a family-shared pass](/help/facility-operators/booking-and-guest-passes/create-a-family-shared-pass).
* Passes are allocated while the membership is **active** (or in a trial). A member added while the membership is past-due or frozen receives their passes when it resumes.
Member limit [#member-limit]
* **Maximum total members** counts the **organizer**. A limit of *4* means the organizer plus 3 family members.
* Allowed range is **2–50**. Leaving **Limit the number of members** unticked means no limit.
* **Admins can exceed the limit when assigning a member directly** — the limit is a guardrail on the customer's self-service flow, not a hard block for staff. The membership integrity report flags any membership that's over its limit or a type that's over capacity.
Who can be a family member [#who-can-be-a-family-member]
* The organizer attaches people from **their own family**: a spouse with their own account, or an accountless dependent (an adult or kid managed on their behalf).
* **One membership per person per club.** Someone who already holds a membership at your club — their own or as a family member elsewhere — can't also be added here.
Lifecycle [#lifecycle]
* **One membership, one lifecycle.** Freeze, cancel, expiry, renewal, and past-due all apply to the whole family automatically — there are no separate per-member subscriptions to manage.
* **Freeze / cancel** suspends or removes family members' access along with the organizer's, and their passes are frozen or archived with the membership.
* **Cancellation warns you** that it removes access for the family members on the membership before you confirm.
* **Event lock.** Once a family member uses the membership to join an event, the customer can no longer remove them or change their type from the customer side — doing so would shift their benefits. **An admin can still make the change.**
Related [#related]
* [Set up a family membership](/help/facility-operators/customers-and-families/set-up-a-family-membership) — the setup walkthrough.
* [How family memberships work](/help/facility-operators/customers-and-families) — the overview.
# Freezing a Membership
During a freeze:
* The member is **not charged**
* Membership **benefits are paused**
* Billing resumes automatically on the predefined day or manually, depending on how the freeze is set up.
***
When to Use Membership Freeze [#when-to-use-membership-freeze]
* Member is traveling or unavailable for a few weeks or months
* Club has a waitlist and the member wants to keep their spot
* Member wants to temporarily pause billing without canceling their membership or having to pay the initiation fee again.
***
How to Freeze a Membership [#how-to-freeze-a-membership]
1. Open the member’s **Profile**.
2. Go to the **Membership** tab.
3. Click **Freeze Membership**.
You’ll then choose how and when the freeze applies.
***
Freeze Options [#freeze-options]
1. Freeze for a Set Period [#1-freeze-for-a-set-period]
Use this when you know when the member will return.
* Choose whether the freeze starts **immediately** or on a **future date**
* Select an **end date** for the freeze
* The system will automatically:
* Pause charges during the freeze period
* Move the **next billing date** to the resume date
* You can adjust the next billing date if you don’t want the member to be charged on the day their membership resumes.
Once the end date is reached, the membership will automatically resume.
***
2. Freeze Indefinitely [#2-freeze-indefinitely]
Use this when the return date is unknown.
* Choose whether the freeze starts **now** or on a **future date**
* No end date is set
* The membership remains frozen until you manually resume it
During this time:
* The member is not charged
* Membership benefits remain inactive
***
Resuming a Frozen Membership [#resuming-a-frozen-membership]
To resume a membership:
1. Open the member’s **Profile → Membership** tab.
2. Click **Resume Membership**.
3. Choose the **next billing date**:
* Resume and charge immediately, or
* Schedule billing for a future date
Once resumed:
* Billing continues based on the selected date
* Membership benefits are restored from that date forward
You can also adjust the next billing date if needed (for example, to account for unused time).
***
Important Notes [#important-notes]
* Members **do not have access to membership benefits** while their membership is frozen.
* Members are **not charged** during the freeze period.
* You can always:
* Resume a membership early
* Change the next billing date
* Cancel a scheduled freeze if plans change
***
The Freeze Membership feature gives clubs flexibility to support members without cancellations, while keeping billing and access fully under control.
# How family memberships work
A **family membership** lets one customer — the **organizer** — put their family on a single membership instead of buying a plan for each person. Everyone rides the same membership, so there's **one bill** and one lifecycle: freezing, cancelling, renewing, or a missed payment applies to the whole family automatically. Family members are never billed separately.
Family memberships are part of the **Memberships** system. You turn a plan into a family plan on the plan itself (no separate setting elsewhere). You need the membership permission to edit plans.
What you can offer [#what-you-can-offer]
* **One membership for the whole family.** The organizer buys a plan and attaches their family to it. There are no separate subscriptions per person.
* **A member limit (optional).** Cap how many people can be on the membership — *Maximum total members* counts the organizer. Leave it off for no limit.
* **Member types (optional).** Define named types — e.g. *Adult*, *Kid* — each with its own rule set and its own booking passes. With no types, every family member just gets the membership's own rule set.
* **Self-service or admin-managed.** By default the customer manages their own family from their account. You can switch that off so only your staff add or remove members.
Who can be on a family membership [#who-can-be-on-a-family-membership]
The organizer attaches people from **their own family** — a spouse with their own account, or an accountless dependent (an adult or kid you manage on their behalf). Each person can hold **only one membership per club**, so someone who already has their own membership at your club can't also be added as a family member here.
How rule sets and passes reach each person [#how-rule-sets-and-passes-reach-each-person]
| Who | Rule set | Booking passes |
| ----------------------- | --------------------------------------------------------- | --------------------- |
| **Organizer** | the plan's own rule set | the plan's own passes |
| **Member on a type** | the type's rule set (or the plan's, if the type has none) | the type's passes |
| **Member with no type** | the plan's own rule set | none |
The full breakdown — including capacity, "Same as membership", and the billing-period-only rule for type passes — is in [Family member types, rule sets & passes](/help/facility-operators/customers-and-families/family-member-types-rule-sets-and-passes).
Where you'll see family on a membership [#where-youll-see-family-on-a-membership]
* **The Family members card** on the membership's detail page — the current roster, with each person's type.
* **A warning when you cancel** — cancelling tells you it also removes access for the family members on the membership.
* **Per-member history** — each customer's membership history shows the family memberships they've held.
Start here [#start-here]
* **[Set up a family membership](/help/facility-operators/customers-and-families/set-up-a-family-membership)** — turn on the switch, set a limit, add member types, and choose who manages the roster.
* **[Family member types, rule sets & passes](/help/facility-operators/customers-and-families/family-member-types-rule-sets-and-passes)** — exactly who gets which rule set and which passes, and the limits that apply.
* For the customer's side, see **[Add family members to your membership](/help/players/customers-and-families/add-family-members-to-your-membership)**.
# Selling a membership to customers
Steps to Add New Members [#steps-to-add-new-members]
1. Click on the **Users** tab from the left-hand menu.
2. Find/Create their profile
* If it’s an existing customer, use the search bar to find them by name or email. Click their name to open their profile.
* If it’s a new customer (the person hasn’t interacted with your club yet), hit **Add New Customer.** Type in their email address, their name — that’s it, their profile is created.
3. In the user’s profile, click the **Membership** tab.
4. Hit **Assign Membership**. A dropdown will list options of your memberships.
5. Pick the right membership.
6. Choose how to handle payment.
* **Now**: Charges them today, starting the membership immediately, with renewals based on the selected billing cycle—monthly, every 6 months, or annually.
* **Later**: Sets a start date and a first payment date (e.g., a week out). They need to add a payment method on file before that first payment date, or it won’t activate if the charge fails.
* **Never**: Applies it as a comped membership with no cost, good for employees or trial periods. It’ll run until December 31, 2199, unless you set an earlier expiration.
7. if you want to send them a confirmation email, make sure you have the box **“Notify the member about the their new membership vis email”** checked. Otherwise, uncheck it.
8. Click **Create membership**. You’re done — they’re now a member!
***
Helpful Tips [#helpful-tips]
* **Waiver Check**: If their waiver status shows “**Not Signed**,” send them a URL or QR code to fill it out.
* **Payment Setup**: If they don’t have a payment method, you can add one in their profile or ask them to do it via their “**My Profile**” page.
# Set up a family membership
Turn one of your membership plans into a **family membership** so a customer can put their family on it. *(About 5 minutes. You need an existing membership plan and the membership permission.)*
Family settings live on the membership plan itself, under **Memberships**. There's no separate feature to switch on elsewhere.
Before you begin [#before-you-begin]
* The plan you want to offer to families already exists as a membership plan.
* Decide whether members should be grouped into **types** (e.g. *Adult*, *Kid*) with different rule sets or passes — or whether every family member should just get the plan's own rule set.
Steps [#steps]
1. Open **Memberships** in the admin panel and select the plan you want to offer to families. The plan's edit screen opens.
2. Turn on **Family membership**. Its description reads *"Let the customer share this membership with family members."*
3. *(Optional)* Tick **Limit the number of members** and set **Maximum total members**. This number is the **total people on the membership, counting the organizer** — so a value of *4* means the organizer plus 3 family members. Allowed range is 2–50. Leave the box unticked for no limit.
> \[!NOTE]
> "Maximum total members" includes the organizer. If a family of four should all be on the plan, set it to *4*, not *3*.
4. *(Optional)* Under **Family member types**, add a type for each kind of member you want to treat differently. For each type set:
* a **Type name** (e.g. *Adult*, *Kid*);
* an optional **capacity** (how many people can hold this type — leave blank for unlimited);
* a **Rule set** — choose one, or leave it as *Same as membership* to use the plan's own rule set;
* optional **booking passes** for people on this type.
With no types defined, every family member simply gets the plan's own rule set and no per-person passes.
5. Choose who manages the roster with **Let customers manage their own family members**:
* **On** (default) — the customer adds and removes their own family members from their account.
* **Off** — only your staff manage the roster. The customer sees a read-only note instead; you can customise it (the default is *"Contact the club to manage family members on this membership."*).
6. **Save** the plan.
What happens next [#what-happens-next]
The plan is now a family membership. At checkout the customer can add family members, and — if self-management is on — they can manage the roster from their membership page afterward. Everyone they add rides this one membership: **no member is billed separately**, and a freeze, cancellation, or renewal applies to the whole family.
Good to know [#good-to-know]
* **Members are free.** Family members never get their own invoice — there is one bill, the organizer's.
* **Editing a plan that already has subscribers is limited.** Once customers are on the plan you can't turn family off, lower the member limit below what's already in use, or change a type's rule set, passes, or capacity in ways that would strip something from people already on it. Raising the limit and adding new types are fine.
* **Type passes use the billing-period cadence.** Booking passes on a member type are granted for the membership's billing period; scheduled allocation cadences aren't available on types.
If something goes wrong [#if-something-goes-wrong]
* **You don't see the Family membership switch** — it only appears on **membership** plans. Make sure the plan is a membership plan, not another product type.
* **Save is blocked on the member limit** — *Maximum total members* must be between 2 and 50, or untick **Limit the number of members** for no limit.
* **A type won't save** — give every type a **Type name**; a blank name is rejected.
Related [#related]
* [Family member types, rule sets & passes](/help/facility-operators/customers-and-families/family-member-types-rule-sets-and-passes) — who gets which rule set and passes.
* [Add family members to your membership](/help/players/customers-and-families/add-family-members-to-your-membership) — the customer's side.
# Upgrading / Downgrading Membership
🔁 When to Use It [#-when-to-use-it]
Use this feature to:
* Move a member from **Monthly** to **Annual** billing (or vice versa).
* Upgrade a member to a higher-tier plan.
* Schedule a downgrade to a lower-tier plan at their next renewal date.
***
⚙️ How to Change a Membership [#️-how-to-change-a-membership]
1. Go to the member’s **Profile**.
2. Open the **Membership** tab.
3. You’ll see their current membership details — including **start date** and **next renewal date**.
4. Click **Change Membership**.
5. Select the new **membership type** and **plan**.
6. Click **Continue**.
***
⏰ Choose When to Apply the Change [#-choose-when-to-apply-the-change]
When upgrading, you’ll see **three options** for when to apply the new membership:
1. At Next Renewal Date (Recommended) [#1-at-next-renewal-date-recommended]
* The membership will switch automatically on the next billing date.
* No charge is processed today.
* On the renewal date, the new membership plan and price will apply.
✅ *This is the most common option for upgrades and plan changes.*
***
2. Effective Now [#2-effective-now]
* The member’s plan changes immediately.
* The system automatically calculates a **prorated amount** based on the unused days from the current plan.
* The member is charged the **difference** between the remaining value of their old plan and the price of the new one.
* Starting from the next billing cycle, they’ll be charged the **full amount** for the new plan.
***
3. Custom Date [#3-custom-date]
* Choose any date in the future to schedule the change.
* The system calculates the **prorated amount** as of that date and shows you the expected charge.
* Click **Schedule Update** to confirm.
* The membership will automatically update on that date.
***
⬇️ Downgrading a Membership [#️-downgrading-a-membership]
When downgrading (moving to a lower plan):
* You can only schedule the change for the **next renewal date**.
* No refunds or partial adjustments are made for the current billing period.
* On the renewal date, the new lower-tier membership will automatically take effect.
This policy helps prevent mid-cycle refunds and keeps billing consistent.
***
🔄 Reviewing or Canceling Scheduled Updates [#-reviewing-or-canceling-scheduled-updates]
After scheduling an upgrade or downgrade:
* You’ll see both the **current membership** and the **upcoming change** listed in the member’s profile.
* If the member changes their mind or you made an error, you can click **Cancel Update** to revert the change.
***
✅ That’s it! You can now easily manage membership changes — whether it’s an upgrade, downgrade, or plan switch — without canceling or re-adding members.
# How OpenCourt sends your club's emails (overview)
Every booking confirmation, event reminder, and receipt OpenCourt sends carries your club's identity. This
page explains its three parts and where a customer's reply goes.
All of it lives under **Settings → Email settings**.
The three parts of your email identity [#the-three-parts-of-your-email-identity]
| Part | What the customer sees |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sender name** | The name in their inbox, such as *Bocce House*. Defaults to your club name. |
| **From address** | The address the email comes from. Defaults to *[notifications@getopencourt.com](mailto:notifications@getopencourt.com)*. You can send from your own domain instead. |
| **Reply-to email** | Where their reply goes when they click **Reply**. |
Where does a customer's reply go? [#where-does-a-customers-reply-go]
* **If you set a reply-to email**, replies go there.
* **If you send from your own domain and have no reply-to**, replies go to your From address.
* **If neither is set, replies do not reach your club.**
A customer who answers "your court is booked for Saturday" expects your front desk to read it. Set a reply-to
— see [Set your email sender name and reply-to address](/help/facility-operators/emails-and-notifications/set-your-email-sender-name-and-reply-to).
Does this change my campaigns? [#does-this-change-my-campaigns]
If OpenCourt runs email campaigns for your club, they keep their own sender name and reply-to, shown in the
**Campaign settings** card at the bottom of the page. The From address is the one thing they share: once you
choose an address on your own domain, campaigns send from it too.
To change your campaign settings, email [support@getopencourt.com](mailto:support@getopencourt.com).
Guides in this collection [#guides-in-this-collection]
* [Set your email sender name and reply-to address](/help/facility-operators/emails-and-notifications/set-your-email-sender-name-and-reply-to) — the
five-minute setup every club should do.
* [Send emails from your own domain](/help/facility-operators/emails-and-notifications/send-emails-from-your-own-domain) — replace
*[notifications@getopencourt.com](mailto:notifications@getopencourt.com)* with an address at your own domain, using two DNS records.
# Send emails from your own domain
Send your booking and event emails from an address at your own domain, such as *[bookings@yourclub.com](mailto:bookings@yourclub.com)*
instead of *[notifications@getopencourt.com](mailto:notifications@getopencourt.com)*. You add the domain, publish two DNS records, then choose the
address. *(About ten minutes of setup, then up to a few hours of waiting for DNS.)*
This lives under **Settings → Email settings**. You need access to your club's settings in OpenCourt **and**
the ability to add DNS records for your domain.
Before you begin [#before-you-begin]
* **A domain your club owns**, such as *yourclub.com*. A Gmail, Yahoo, or Outlook address does not work.
* **Access to your domain's DNS records**, usually at the company your domain is registered with. If someone
else manages your website, send them this article. They add the two records, and you click the verify button.
* Nothing changes for your customers while you wait. Your booking and event emails keep sending from
OpenCourt's address until the domain is verified.
Add your sending domain [#add-your-sending-domain]
1. Go to **Settings → Email settings**.
2. In the **Sending domain** card, type your domain into **Domain** — for example *yourclub.com*.
3. Click **Add domain**.
The card now shows **Waiting for DNS records** and the records to publish.
Pick the domain carefully. Changing it later means removing it and verifying the new domain from scratch.
Add the two DNS records [#add-the-two-dns-records]
The card lists a **DKIM** record and a **Return-Path** record. Each shows a **Type**, a **Host**, and a
**Value**, with a copy button beside the host and the value.
1. Open your DNS provider — the company your domain is registered with.
2. Add a record of type **TXT**. Paste the DKIM **Host** into the name or host field, and the DKIM **Value**
into the value field.
3. Add a record of type **CNAME**. Paste the Return-Path **Host** into the name field, and the Return-Path
**Value** into the target or points-to field.
4. Save both records.
Many DNS providers add your domain to whatever you type in the host field. If yours does, paste only the
part **before** your domain — for *pm-bounces.yourclub.com* enter *pm-bounces*. Copy the value exactly as
shown, with no extra spaces or quotation marks.
Should I add the DMARC record? [#should-i-add-the-dmarc-record]
Below the two records, the card can show a **DMARC** row. It is optional — your domain verifies without it —
but it helps your emails reach the inbox.
* **If the card says DMARC is already published**, there is nothing to do.
* **If the card recommends one**, add a record of type **TXT** with the host and value the card shows.
Choose your From address [#choose-your-from-address]
You do not have to wait for DNS. Choose the address now, and your booking and event emails switch to it as
soon as the domain is verified.
**If OpenCourt runs email campaigns for your club, wait until the domain is verified.** Campaigns switch to
the new address as soon as you click **Save**.
1. In the **Sender identity** card, find **From address**.
2. Click **Choose address**.
3. Type the part before the @ — for example *bookings*. Your domain is filled in after it.
4. Click **Save**.
Until the domain verifies, the row shows **Waiting for verification**, and your booking and event emails keep
sending from *[notifications@getopencourt.com](mailto:notifications@getopencourt.com)*.
Verify the domain [#verify-the-domain]
1. In the **Sending domain** card, click **Check verification**.
2. If both records are visible, the card turns green: **Domain verified**. Your emails now send from your
From address.
3. If one or both are not visible yet, the card stays amber and tells you it is still waiting. DNS changes
take anywhere from a few minutes to a few hours to spread. Wait and check again.
You do not have to come back to the page. OpenCourt checks the records on its own and verifies the domain when
they appear.
What each status means [#what-each-status-means]
| Sending domain card | From address row | What your emails do |
| --------------------------- | ---------------------------- | ----------------------------------- |
| **Waiting for DNS records** | **Waiting for verification** | Send from OpenCourt's address |
| **Domain verified** | **Verified** | Send from your address |
| **Re-checking your DNS** | **Re-checking** | Still send from your address |
| **Branded sending paused** | **Paused** | Send from OpenCourt's address again |
If a record is later deleted or changed, OpenCourt emails your club's **Reply-to email** with the records to
republish. To send this alert to more people, such as whoever manages your DNS, add them to **Sending Domain
Alerts** under **Settings** > **Admin Team** > **Notifications**. Your emails never stop — only the From
address changes back to OpenCourt's until you fix it.
After your domain verifies [#after-your-domain-verifies]
* **Replies follow your From address.** If you have not set a separate reply-to, customer replies go to your
From address. To send them somewhere else, see
[Set your email sender name and reply-to address](/help/facility-operators/emails-and-notifications/set-your-email-sender-name-and-reply-to).
* **Keep the records in place.** If you delete or change either record, your emails switch back to OpenCourt's
address.
* **Send yourself a test.** Once the domain is verified and you have chosen a From address, a **Send test
email** button appears next to **Check verification**. It sends a message to your own admin email address, so
you see the email as a customer would.
Change your From address [#change-your-from-address]
In the **Sender identity** card, click **Change** on the **From address** row, type the new part before the
@, and click **Save**. The domain stays the same, so there is nothing to verify again.
Go back to OpenCourt's address [#go-back-to-opencourts-address]
In the **Sending domain** card, click **Remove domain**, then confirm with **Remove domain**. Your emails go
back to sending from *[notifications@getopencourt.com](mailto:notifications@getopencourt.com)* straight away, and your From address on that domain is
cleared. You can add the domain again at any time.
If something goes wrong [#if-something-goes-wrong]
* **"Enter a domain like yourclub.com or mail.yourclub.com"** — type only the domain, without *https\://*.
* **"This domain is already connected to another club on OpenCourt"** — if that is wrong, email
[support@getopencourt.com](mailto:support@getopencourt.com).
* **The From address row has no Choose address button** — add your domain in the **Sending domain** card
first.
* **Verification still fails after a day** — check the host field at your DNS provider. The most common cause
is a doubled domain, such as a record saved at *pm-bounces.yourclub.com.yourclub.com*. Also compare the value
character for character against the card.
* **A verified domain changed to Branded sending paused** — one of the two records was deleted or edited.
Republish it from the card, then click **Check verification**.
* **Check verification still shows a record as not found after you republished it** — OpenCourt looks the
record up itself, and a DNS change can take a few hours to show everywhere. Wait and check again. OpenCourt
also re-checks every hour and switches your emails back on its own.
Related [#related]
* [How OpenCourt sends your club's emails (overview)](/help/facility-operators/emails-and-notifications)
* [Set your email sender name and reply-to address](/help/facility-operators/emails-and-notifications/set-your-email-sender-name-and-reply-to)
# Set your email sender name and reply-to address
Set the name customers see in their inbox and the address their replies reach, so a question about a booking
lands at your front desk. *(About five minutes, including the test email.)*
This lives under **Settings → Email settings**. Any admin who can open your club's settings can change it.
Before you begin [#before-you-begin]
* An inbox at your club that someone reads, such as *[hello@yourclub.com](mailto:hello@yourclub.com)*.
Set your sender name [#set-your-sender-name]
1. Go to **Settings → Email settings**.
2. In the **Sender identity** card, find **Sender name**. It shows your club name with *(default)* next to
it.
3. Click **Override**, type the name you want, and click **Save**.
Use the name customers already know you by. To go back to your club name, clear the field and click **Save**.
Set your reply-to address [#set-your-reply-to-address]
1. In the same **Sender identity** card, find **Reply-to email**.
2. Click **Set reply-to**.
3. Type your club's address and click **Save**.
Replies to booking confirmations, event reminders, and receipts now go to that inbox.
Confirm the inbox receives mail [#confirm-the-inbox-receives-mail]
A typo here is hard to notice: your emails keep sending, but the replies never arrive. Send a test.
1. In the **Sender identity** card, find your saved **Reply-to email**.
2. Click **Send test email** under the address.
3. Open that inbox and confirm the message arrived.
The page then shows **Test sent**. If the test bounces, it shows **Bounced**. Correct the address and send the
test again.
What happens if you leave the reply-to empty [#what-happens-if-you-leave-the-reply-to-empty]
If you send from your own domain, replies go to your From address — see
[Send emails from your own domain](/help/facility-operators/emails-and-notifications/send-emails-from-your-own-domain). If you do not, replies do not reach
your club, so set a reply-to.
Does this change my campaigns? [#does-this-change-my-campaigns]
No. If OpenCourt runs email campaigns for your club, their sender name and reply-to stay as they are. To
change them, email [support@getopencourt.com](mailto:support@getopencourt.com).
If something goes wrong [#if-something-goes-wrong]
* **The test email bounced** — the inbox does not exist, is full, or rejects outside mail. Confirm the address
with whoever runs your email, then send the test again.
* **The test email never arrived and did not bounce** — check the spam folder first. If it is not there,
ask your mail provider to allow mail from OpenCourt.
* **You cannot find Email settings** — your admin account cannot open club settings. Ask an owner at your club
to give you access.
Related [#related]
* [How OpenCourt sends your club's emails (overview)](/help/facility-operators/emails-and-notifications)
* [Send emails from your own domain](/help/facility-operators/emails-and-notifications/send-emails-from-your-own-domain)
# Auto-Cancellation for Events
How It Works [#how-it-works]
When creating an event (e.g., open play, clinic), admins can enable **Auto-Cancellation**:
1. [**Create an Event as usual**](/help/facility-operators/events-and-programs/creating-an-event)
2. **Enable Auto-Cancellation**
* In the Participation block toggle on **Enable Auto-Cancellation**.
* Set the **minimum number of participants** required for the event.
* Example: 4 participants minimum.
* **Set the Cancellation Check Time —** Choose how many hours before the event the system should check registrations.
* Example: Check **2 hours before** start time.
3. **Save the Event**
* Once created, the event will display a warning for both admins and users that it may be canceled if minimum participation is not met.

***
What Happens if the Event is Canceled? [#what-happens-if-the-event-is-canceled]
* If the participant requirement is not met by the cancellation check time:
* The event will be **automatically canceled**.
* Participants who already registered and paid will receive a **refund**.
* Users will no longer see the event in the schedule.
* Admins will see it on Events & Programs page
***
Example [#example]
* You create an **Open Play** requiring **at least 4 players**.
* Auto-cancellation is set to **2 hours before start time**.
* By the check time, only **3 players have registered**.
* The system automatically cancels the event and issues refunds to those 3 players.
***
Key Notes [#key-notes]
* Admins see a warning on the event page that auto-cancellation is enabled.
* Players also see a warning before registering, so they know the event might be canceled if it doesn’t meet the minimum sign-ups.
* Everything else in event creation (pricing, courts, time slots) works as usual.
# Creating a Multi-Date Event (e.g. League)
When you create a league in OpenCourt, you’ll use the **multi-date event** feature so all matches are scheduled under one event.
Step 1 — Start a New Event [#step-1--start-a-new-event]
1. In the left-hand menu, click **Events & Programs**.
2. Click **New Event**.
3. Enter your **Event Name** (e.g., *Ladder League*) and a **Description**.
4. Fill out the rest of the event details (capacity, pricing, etc.) as you would for [any regular event.](/help/facility-operators/events-and-programs/creating-an-event)
***
Step 2 — Add Multiple Dates [#step-2--add-multiple-dates]
1. In the **Time Slot** section choose the **day, time, and courts** for the first match.
* Example: Saturday, 7:30 PM – 9:30 PM, Courts 1–4.
2. Right under that block you’ll see **Add Time Slot** button. Click it to add the next date.
3. Repeat for every date in the league schedule — these can be at the same time each week or different days/times as needed.
***
Step 3 — Create the Event [#step-3--create-the-event]
1. Review all dates to ensure the schedule is correct.
2. Click **Create Event**.
3. Your league will now show all scheduled matches under one event
***
Important [#important]
Participants who register for this multi-date event will be **automatically enrolled in every match for the entire duration of the league**.
# Creating a private event
Option 1: Private Event (Visible but Closed to Public Registration) [#option-1-private-event-visible-but-closed-to-public-registration]
Use this option if you want people to **see the event on the schedule** but **not be able to join it**.
**Example:** A *Birthday Party* that shows up on the club calendar, so other players know the courts are booked — but only invited guests can attend.

**How to create it:**
1. Go to **Events & Programs → Create Event**.
2. Enter the event name and details.
3. In the **Event Settings** section, **toggle off “Allow Public Registration.”**
4. Set your date, time, and courts as usual.
5. Click **Create Event.**
💡 You can:
* Add guests manually as an admin.
* Share a **private link** with the host or group, so only those invited can view and join.
* Everyone else will see the event name and description, but won’t be able to register.
***
Option 2: Fully Private Event (Completely Hidden) [#option-2-fully-private-event-completely-hidden]
Use this option when you don’t want anyone outside the invited group to see event details at all.
**Example:** A *Corporate Team Building Night for BMW* where event details, participants, and names are kept confidential.
**How to create it:**
1. Go to **Events & Programs → Create Event**.
2. In **Event Settings**, **toggle on “Make Event Private.”**
3. (Optional) Set participant limits and pricing.
4. Choose date, time, and courts, then click **Create Event.**
💡 In this case:
* The schedule will simply show **“Private Event”** with a grayed-out time slot.
* No event details, names, or participant lists will be visible to others.
* Add guests manually as an admin.
* Share a **private link** with the host or group, so only those invited can view and join.
***
When to Use Private Events [#when-to-use-private-events]
* **Corporate buyouts** (team-building or company tournaments)
* **Birthday parties or celebrations**
* **Invite-only clinics or member socials**
* **Private group practices or lessons**
***
✅ With Private Events, you can easily block courts, manage guests, and maintain privacy—all while keeping your club schedule organized and transparent.
# Creating an event
Events are Open Plays, Socials, Clinics, Tournaments, Leagues, Opening Parties, etc: anything that your customers can join as a participant. [How are Events different from Reservations?](/help/facility-operators/court-bookings/reservations-vs-events)
OpenCourt lets you publish and manage any kinds of event in just a few clicks.
1. Go to the **Schedule** page and click on a time that the event is supposed to start, at the court (or one of the courts) where event will be taking place.
2. The New Booking window will appear.
* Date, Start time and court will already be pre-selected
* Select the End Time or one of the Duration options
* Select additional courts, if needed. If the event is taking place over multiple days (like a League or a multi-day Tournament), or it starts and ends on different courts at different times, you’ll be able to adjust the time slots later.
* Select the **Reservation Type** as **Event**.
* Press **Continue**.
3. The **New Event** page will appear.
* **Event Name** & **Description**: will be displayed to the user.
* **Event Type**: will be displayed to the user; also you can later filter by the event in the various places in the admin panel; simplifies event filtering for your customers on their app’s Join tab.
* Turn on **Allow Public Registration** to allow customers to join (in most cases you want it On).
* Turn on **Make Event Private** if you’re looking to make event details hidden from anyone who sees it on the schedule; nobody would be able to see event details or join it unless you share the **Private Invitation Link** with them.
* **Max Capacity**: event will stop accepting new signups once all spots are filled.
* **Pricing**: events can be free or have a specific price. You can specify a price for each Membership Group. This is the price that a member of such Membership Group (or a non-member) would pay to join the event. Please note that pricing is set as a specific figure for the event as a whole; it’s not a per hour pricing.
* **Signup Questions**: helpful for tournaments and leagues where you’re wanting to collect additional information, such as the partners name, team name, or a t-shirt size. You can make as many signup questions as you like for the event, and mark them as required or optional.
* **Skill Rating**: you can set up recommended or enforced skill rating requirements for your event.
4. Choose time slots
* Time slot will be prefilled if you started your process already selecting a time on the **Schedule** page. You can add, edit, remove time slots are you see fit.
5. Press **Create Event**.
Your event will now appear in both the **Schedule** and **Events & Programs** pages of the admin panel. It will also show up for the user on the **Book** and **Join** tabs of the web and mobile application.
***
You can also create your Event by pressing **New Event** button on the **Events & Programs** page. You’ll follow a very similar process as above, except you’ll specify the date, time, and courts as Time Slots on the page as opposed to pre-selecting them.
# Creating Events with Divisions
Note: a user can sign up only for a single Division at a time in any individual event. If you’re looking to allow the user to sign up for multiple Divisions at the same time, we suggest creating multiple events.
How to Create an Event with Divisions [#how-to-create-an-event-with-divisions]
1. [**Start a New Event**](/help/facility-operators/events-and-programs/creating-an-event) **as usual**
* Go to **Events & Programs** and click **Create Event**.
* Enter your event name and choose the event type.
* Set capacity (total number of participants) and pricing as usual
2. **Enable Divisions**
* Under the **Pricing** block, you’ll see a section for **Event Divisions**.
* Toggle **Event Divisions** on and click **Add New Division**.
* Create each division and set participant limits for each.
3. **Add Time Slots**
* Choose the date and time for your event, then click **Create Event**.
***
Managing Participants as an Admin [#managing-participants-as-an-admin]
* When adding participants, you’ll now see a **Division column** with a dropdown menu.
* Select which division each participant belongs to.
***
User Experience [#user-experience]
* When signing up, participants will see the **number of spots left in each division**.
* During registration, they must select a division before completing payment.
* Each participant will be listed under their chosen division once registered.
***
✅ That’s it! Your event is now organized with clear divisions, making it easier for players to join the right group and for admins to manage balanced events.
# Creating recurring event series
Step 1 — Start a New Event [#step-1--start-a-new-event]
1. In the left-hand menu, click **Events & Programs**.
2. Click **New Event**.
***
Step 2 — Add Event Details [#step-2--add-event-details]
Enter all the event details like in a [regular event](/help/facility-operators/events-and-programs/creating-an-event).
***
Step 3 — Set Up the Recurring Schedule [#step-3--set-up-the-recurring-schedule]
1. In the **Time Slot** section, click the **Recurring Series** tab.
2. Choose your **day and time** — for example:
* **Day:** Saturday
* **Time:** 6:00 AM – 8:00 AM
3. Select the **Courts** — e.g., Courts 1 to 4.
4. Set the **End Date** — for example, until the end of September.
***
Step 4 — Create the Event Series [#step-4--create-the-event-series]
1. Once all details are set, click **Create Event Series**.
2. Your events will now appear in your **Events & Programs** list and on the **Schedule**.
***
Step 5 — Manage Individual Events in the Series [#step-5--manage-individual-events-in-the-series]
* Each event in the recurring series is treated as a **separate event**.
* You can open any date in the series to:
* View participants
* Add players
* Edit event (for that specific date)
# Editing Programs (Event Series)
Quickly update multiple upcoming events in a program without having to edit or recreate each one manually. This is especially useful if you’re running recurring events like weekly open plays or clinics and need to adjust times, courts, or a number of participants mid-season.
And you can also **add new events** to an existing program whenever needed — for example, to extend the series or insert an extra session between existing dates.
***
When to use “Bulk Edit” [#when-to-use-bulk-edit]
Use Bulk edit when you need to:
* Change **time slots**, **courts** or **participant limits** for multiple future events at a time.
In this scenario, you can select one or multiple instances of the Program (events), and apply these changes to them quickly and easily.
When to use “Edit Settings” [#when-to-use-edit-settings]
Use **Edit settings** when you need to change details that apply across sessions—like the event name/description, privacy, pricing, or requirements.
* Update **event settings** like pricing, public registration, divisions, or skill ratings.
* Add or remove **sign-up questions**.
* Modify **event descriptions** or **names** across all sessions.
When to edit Events individually [#when-to-edit-events-individually]
You can choose to edit any given event within the program individually. You can adjust any settings on that individual event – however, keep in mind that editing any event individually makes it ***not*** follow any settings of the Program. In a way, it becomes “detached” from any future updates of the Program, while still technically being a part of it.
***
How to Bulk Edit a Program [#how-to-bulk-edit-a-program]
1. Go to **Events & Programs** from the left-hand menu.
2. Click on **Programs** or **Event Series**.
3. Under the **Active** tab, find the program you want to edit.
4. Click **Bulk Edit**.
5. Select which events you want to modify:
* Choose **All events** in the series,
* Or click the small **arrow icon** to select this event and all events after it (e.g., starting next month).
6. Once selected, click **Apply Changes**.
After confirming your edits, click **Update Event Series**. You’ll see a success message (“Programs bulk edited successfully”) and your changes will appear immediately under **Upcoming Events**.
> **Note:**\
> If you change the time or courts to slots that are already booked, the system will show an overlap warning. Simply choose a different time or court to avoid conflicts.
***
How to Edit Program Settings [#how-to-edit-program-settings]
1. Go to **Events & Programs** → **Event Series**.
2. Open the program and click **Edit settings**.
3. Update any of the following:
* **Name & Description**
* **Public Registration** (toggle on/off)
* **Make Event Private** (from this point forward)
* **Participants Limit**
* **Pricing**
* **Skill Rating** (add/remove)
* **Sign-up Questions** (add/remove)
* **Event Divisions** (add/remove)
4. Click **Update Event Series**.
**Scope of changes:**\
Settings apply only to the upcoming events. After saving, you’ll see a success message and the updates will appear immediately under **Upcoming Events**.
***
Adding or Removing Events in the Series [#adding-or-removing-events-in-the-series]
And you can also **add new events** to an existing program whenever needed — for example, to extend the series or insert an extra session between existing dates:
1. Click **Add New Event to Program**.
2. Choose a new **date**, **time slot**, and **court(s)**.
3. Set the **participants limit**.
4. Click **Create**.
The new event will automatically appear in your program list.
# Event Reminders
***
Setting Up Default Event Reminders (By Event Type) [#setting-up-default-event-reminders-by-event-type]
Default reminders apply to **all new events** you create for a specific event type.
1. Go to **Settings**.
2. Open **General Settings**.
3. Scroll to **Reservations & Event Reminders**.
4. Choose which **event types** should have reminders (e.g. Open Play, Clinics, Leagues, Tournaments).
5. Set how long before the event the reminder should be sent:
* Minutes (e.g. 90 minutes before)
* Hours (e.g. 3 hours before)
* Days (e.g. 1 or 2 days before)
These settings will apply to **all newly created events** of that type going forward (they do not apply retroactively to past events).
***
Customizing Reminders for a Specific Event [#customizing-reminders-for-a-specific-event]
If you want different reminder behavior for one specific event you can do it when you create this event or when you edit it:
1. In **Event Settings**, find **Event Reminders** (under the event type).
2. Toggle reminders **ON or OFF** for that event.
3. Adjust the reminder timing if needed.
This allows you to:
* Enable reminders for one event only
* Disable reminders for a specific event while keeping them on for others
* Override the default timing for that event
***
How Reminders Are Sent [#how-reminders-are-sent]
When reminders are enabled:
* Participants receive an **email reminder**
* The message includes:
* A friendly reminder
* Event name and type
* Date, time, and location
* Other relevant event details
Reminders are sent automatically based on the timing you set.
***
When to Use Event Reminders [#when-to-use-event-reminders]
* Leagues or tournaments with long signup periods
* Clinics that require advance registration
* Events where attendance is critical
* Any event where reducing no-shows improves the experience
***
Key Notes [#key-notes]
* Event reminders can be controlled at both:
* The **event type level**
* The **individual event level**
* You can turn reminders on or off anytime before the event starts.
***
Event Reminders give clubs flexible control over communication and help ensure players show up informed and on time.
# Event Tags
***
Setting Up Tags [#setting-up-tags]
Creating Tags [#creating-tags]
1. Go to **Settings → Event Tags**
2. Click **Create Tag**
3. Enter a name (e.g., "Beginner", "Advanced", "Ladies", "Youth")
4. A color is automatically assigned — you can change it by clicking the color swatch
5. Click **Create**
Tags are unique per club — you can't have two tags with the same name.
Managing Tags [#managing-tags]
On the Event Tags settings page you can:
* **Rename** a tag by clicking its name
* **Change the color** by clicking the color swatch
* **Reorder** tags by dragging — this controls the display order everywhere tags appear
* **Delete** a tag — the system shows how many events and booking passes will be affected before you confirm

Assigning Tags to Events [#assigning-tags-to-events]
From the Event Editor [#from-the-event-editor]
1. Open an event for editing in the admin panel
2. In the event settings area, find the **Tags** section
3. Click to open the tag selector
4. Search for and select one or more tags — they appear as colored badges
5. You can also create a new tag inline if the one you need doesn't exist yet
Tags are saved immediately when you select or deselect them.
From the Event Details Modal [#from-the-event-details-modal]
When viewing an event's details in the admin panel, tags appear as badges. Click the edit button next to the tags to add or remove them.
Tags in the Admin Events List [#tags-in-the-admin-events-list]
Tags appear as colored badges in the events table, making it easy to visually scan which events belong to which categories.
***
Filtering Events on the User Join Page [#filtering-events-on-the-user-join-page]
This is the main user-facing benefit of tags. Instead of the default event type tabs (Open Play, Clinics, Tournaments, etc.), you can show your own custom tag-based tabs on the Join page.
Two Filter Modes [#two-filter-modes]
The Join page supports two filter modes, configured in **Settings → Event Tags**:
1. Event Type Tabs (Default) [#1-event-type-tabs-default]
The standard tabs based on event type:
* Open Play
* Clinics
* Tournaments
* Leagues
* Other
This is the default mode if you haven't set up tag filtering.
2. Tag Filter Tabs [#2-tag-filter-tabs]
Your custom tags replace the default tabs. Members tap a tag to see only events with that tag. An "All Events" tab shows everything.
Setting Up Tag Filter Tabs [#setting-up-tag-filter-tabs]
1. Go to **Settings → Event Tags**
2. Switch the filter mode from **Event Type Tabs** to **Tags Filter**
3. For each tag you want to appear as a tab on the Join page, toggle the **Tab Filter** switch on
4. Not every tag needs to be a tab — you might have tags for internal organization that you don't expose to members
5. Drag to reorder the tabs — this is the order members will see them
6. Save your changes
How It Works for Members [#how-it-works-for-members]
When tag filtering is enabled:
* The Join page shows an **All Events** tab plus one tab per tag marked as a tab filter
* Tapping a tag tab shows only events that have that tag assigned
* Events can have multiple tags — they'll appear under each matching tab
* The "All Events" tab shows everything (unless an event is specifically hidden — see below)
Open Games Tab [#open-games-tab]
Regardless of which filter mode you use, you can optionally enable an **Open Games** tab that appears alongside the other tabs. This shows member-created open games/reservations. You can also customize the tab name (e.g., "Open Bookings").
Configure this in the same Event Tags settings page.
***
Restricting Booking Passes by Tag [#restricting-booking-passes-by-tag]
Tags integrate with the booking pass system. When creating or editing a booking pass template, you can restrict the pass to only work for events with certain tags.
How It Works [#how-it-works]
1. Go to **Booking Passes** in the admin panel
2. Create or edit a pass template
3. In the restrictions section, select which event tags this pass applies to
4. Save the template
When a member tries to use a booking pass for an event, the system checks:
* If the pass has **tag restrictions**: the event must have at least one matching tag
* If the pass has **event type restrictions** (e.g., Clinics only): the event must match the type
* If the pass has **both**: the event needs to match **either** the tag or the event type (OR logic)
* If the pass also has **time restrictions**: the event must additionally fall within the allowed schedule (AND logic)
Example [#example]
A club creates three booking passes:
* **"Beginner Clinic Pass"** — restricted to tag "Beginner" → only works for events tagged "Beginner"
* **"All Clinics Pass"** — restricted to event type "Clinic" → works for any clinic regardless of tags
* **"Ladies Night Pass"** — restricted to tag "Ladies" → only works for events tagged "Ladies"
A member with the "Beginner Clinic Pass" tries to join an advanced clinic — the pass won't apply because the event doesn't have the "Beginner" tag.
***
Tips [#tips]
* **Start simple** — Create a few broad tags ("Beginner", "Intermediate", "Advanced") and expand from there based on what members search for
* **Use tab filters for the categories members care about** — If members frequently ask "which clinics are for beginners?", make "Beginner" a tab filter
* **Keep internal tags off the tab filter** — Tags like "Needs Review" or "Premium" can be useful for admin organization without appearing on the Join page
* **One event, multiple tags** — An event can be tagged both "Beginner" and "Ladies", appearing under both tabs
* **Tag colors matter** — They show up as badges in the admin list and help with quick visual scanning. The system auto-picks contrasting colors, but you can customize them
* **Booking pass restrictions** — Combine tag restrictions with time restrictions for precise control (e.g., "Beginner Pass" that only works on weekday mornings for events tagged "Beginner")
# Event Waitlist
***
Enabling a Waitlist for an Event [#enabling-a-waitlist-for-an-event]
When creating an event:
1. Fill in all the usual event details (name, description, type, pricing, capacity).
2. Scroll to the **Waitlist** section.
3. Toggle **Enable Waitlist** ON.
4. Choose the waitlist type:
* **Simple Waitlist**
* **Sequential Waitlist**
5. Finish creating the event as usual.
***
Simple Waitlist [#simple-waitlist]
A Simple Waitlist notifies everyone on the waitlist at the same time as soon as a spot becomes available, and it is best when you want minimal setup.
How it works [#how-it-works]
* Until the event reaches capacity, it behaves like a normal event.
* Once full, users can no longer join — but they’ll see a **Join Waitlist** button.
* Users can:
* Join the waitlist
* See how many people are currently waiting
* Leave the waitlist at any time
When a spot opens [#when-a-spot-opens]
A spot can open if:
* A participant cancels
* An admin increases event capacity
When this happens:
* **All waitlisted users** receive a push notification and email.
* The event becomes open again.
* Whoever joins first gets the spot.
* The event is also open to the public — not just the waitlist.
Why join the waitlist? [#why-join-the-waitlist]
The advantage is **early notification** — waitlisted users are alerted immediately when a spot becomes available.
***
Sequential Waitlist [#sequential-waitlist]
A **Sequential Waitlist** gives clubs more control by inviting users in order, in small groups or one at a time.
Additional setup required [#additional-setup-required]
When selecting Sequential Waitlist, you’ll configure:
* **How many people are invited at a time** (e.g. 2 people at a time)
* **Invitation interval** (e.g. every 5 minutes)
* Optional: **Open event to public after waitlist is exhausted**
How it works [#how-it-works-1]
* Users are invited **in the order they joined the waitlist**.
* Only the invited group can join during their invitation window.
* If a user joins and takes the spot, **all further invitations stop automatically**.
* If no one joins from :
* The system invites the next group after the set interval.
* Or, if enabled, opens the event to public access after the waitlist is exhausted.
Important rules [#important-rules]
* Only people on the waitlist can join via a Sequential Waitlist, they can’t add guests with them.
* Each waitlisted person must join individually when it’s their turn.
* The earlier a user joins the waitlist, the better their chances.
***
Admin Controls [#admin-controls]
Admins can manage waitlists directly:
* Add users to the waitlist manually
* Remove users from the waitlist
If an admin adds a waitlisted user to the event:
* That user is automatically removed from the waitlist
* The next eligible waitlisted user moves up in line
***
When to Use Each Type [#when-to-use-each-type]
**Use Simple Waitlist if you want:**
* Quick setup
* First-come, first-served access
* Public access as soon as a spot opens
**Use Sequential Waitlist if you want:**
* Controlled invitations
* Priority based on waitlist order
* Less competition when a spot opens
***
The Event Waitlist feature helps clubs maximize attendance, reduce empty spots, and give players a fair chance to join popular events — even when they fill up fast.
# How time slots work for various types of events
When you create a reservation or an event, you’ll inevitably have to deal with the concept of Time Slots.
Time Slots are a combination of Time + Court to which said reservation or event is applied.
Most of your reservations will have a single time slot. You may choose for some reservations to take up multiple courts within the same time slot.
Events will often have more variability.
Time slots do **not** define a separate event. This means, regardless of how many time slots you create for an event, it will still be a single event, with a single list of participants, single title, single description, and so on.
Here are a few helpful examples.
Leagues [#leagues]
In vast majority of cases, users sign up to the whole league once; and the league takes up court time throughout several weeks. For example, every Wednesday 6-8pm on Court 1 and Court 2 for the duration of 6 weeks.
For this scenario, you would create 6 time slots: one for each day of participation. Each time slot would be for a different Wednesday, with 6pm as a start time and 8pm as the end time, with Court 1 and Court 2 selected.
Users would be able to sign up for the league event on the schedule before the first time slot’s time come up. Admin can add and modify participants in the event at any time.
Tournaments [#tournaments]
For each event within a tournament – meaning, for each portion of the tournament that will have a separate list of participant, a separate collection of payment, and so on, you’ll create a separate event on OpenCourt.
In certain cases you can choose to not apply any courts to an event. You can do so within a time slot that you create. When you do that, the event will show up for that day in the user’s **Join** tab and in the admin panel on the **Events & Programs** page on that day but it will not show up on the schedule. You would still be able to copy and share the Invitation Link to the event with your community.
Other cases [#other-cases]
Often you’ll need an event to occupy a different amount of time on different courts. For example, an Open Play that goes 5-9pm; occupying Courts 1, 2, 3, 4 during the 5-8pm period, and scaling down to Courts 1 and 2 during the 8-9pm period. If you’re intending to maintain a single list of participants and the price is the same regardless of what time they show up during the whole period, creating separate time slots within a single event is a wise idea.
# Events & Programs
Everything that appears on your schedule as an organized session rather than a plain court booking: open play, clinics, lessons, tournaments and multi-week leagues, plus the tools for running the people who sign up.
If what you actually want is a single court held for one customer, that is a reservation — see [Court Bookings](/help/facility-operators/court-bookings), and [Reservations vs. Events](/help/facility-operators/court-bookings/reservations-vs-events) for the distinction.
Create something [#create-something]
* [Creating an event](/help/facility-operators/events-and-programs/creating-an-event) — the basic single-session event.
* [Creating a private event](/help/facility-operators/events-and-programs/creating-a-private-event) — an event that is not open to everyone.
* [How time slots work for various types of events](/help/facility-operators/events-and-programs/how-time-slots-work-for-various-types-of-events) — how the schedule turns your settings into bookable slots.
Multi-session programs [#multi-session-programs]
* [Creating recurring event series](/help/facility-operators/events-and-programs/creating-recurring-event-series) — the same session, repeating.
* [Creating a Multi-Date Event (e.g. League)](/help/facility-operators/events-and-programs/creating-a-multi-date-event-eg-league) — one purchase covering several dates.
* [Editing Programs (Event Series)](/help/facility-operators/events-and-programs/editing-programs-event-series) — changing a series after it exists.
* [Creating Events with Divisions](/help/facility-operators/events-and-programs/creating-events-with-divisions) — splitting participants by level or bracket.
Organize and find them [#organize-and-find-them]
* [Event Tags](/help/facility-operators/events-and-programs/event-tags) — label events so customers and rules can find them.
Manage the people [#manage-the-people]
* [Event Waitlist](/help/facility-operators/events-and-programs/event-waitlist) — what happens when an event is full.
* [Auto-Cancellation for Events](/help/facility-operators/events-and-programs/auto-cancellation-for-events) — call off an under-subscribed session automatically.
* [Event Reminders](/help/facility-operators/events-and-programs/event-reminders) — what participants are sent before the session.
* [Sending Emails to Event Participants](/help/facility-operators/events-and-programs/sending-emails-to-event-participants) — message a roster directly.
Integrations [#integrations]
* [Swish Integration - Effortless Game Management](/help/facility-operators/events-and-programs/swish-integration-effortless-game-management)
Related [#related]
* [Court Bookings](/help/facility-operators/court-bookings) — the spaces your events run on.
* [Pricing & Discounts](/help/facility-operators/pricing-and-discounts) — what an event costs, and how to discount it.
# Sending Emails to Event Participants
***
How to Send an Email [#how-to-send-an-email]
1. Open the event from the admin events list
2. Go to the **Participants** tab
3. Click **Send email to participants** in the header area above the participants table
Step 1: Compose Your Message [#step-1-compose-your-message]
The email popup opens with two sections:
**Subject** — Pre-filled as **"\[Event Name] — \[Club Name]"**. This gives recipients immediate context about which event the email relates to.
**Message** — A rich text editor where you write your message.
Step 2: Choose Recipients [#step-2-choose-recipients]
Below the editor, you'll see a list of all recipients. By default, **all confirmed participants and waitlisted members** are selected. Each person has a checkbox — uncheck anyone you want to exclude from this email.
The label shows how many people will receive the email (e.g., "6 will receive this email").
Guests without user accounts are automatically excluded since they don't have email addresses in the system.
Step 3: Review [#step-3-review]
Click **Review** to see a preview of the email before sending. The review step shows:
* **Email preview** — How the email will look to recipients, including:
* An intro line: "You have an update from **\[Club Name]** regarding your upcoming event"
* Your custom message in a left-bordered card
* An **Event Details** card with the event name, date/time, duration, and court/space assignment
* **Recipient list** — The final list of people who will receive the email, with names and email addresses
Step 4: Send [#step-4-send]
Click **Send email** to send. You'll see a confirmation toast:
* **Success**: "Email queued for X recipient(s)"
* **Partial failure**: "X email(s) queued. Y failed to enqueue." (if some addresses had issues)
* **Full failure**: Error message with details
***
Email Log [#email-log]
Every event has an **Email Log** tab in the event detail modal, right next to the Activity Log. This shows all emails related to this event — both admin-sent emails and automatic system notifications (reminders, confirmations, updates).
The Email Log table shows:
* **Date** — When the email was sent
* **Recipient** — Name and email address
* **Subject** — The email subject line
* **Status** — Sent (green), Pending (yellow), Failed (red), or Skipped (gray)
You can search by recipient name or subject, and click the eye icon on any row to preview the full rendered email.
Failed or skipped emails show the error reason in a tooltip when you hover over the status badge.
***
What the Email Looks Like [#what-the-email-looks-like]
Recipients receive a branded email with:
1. **Header** — Club branding
2. **Intro line** — "You have an update from **\[Club Name]** regarding your upcoming event."
3. **Your message** — The custom content you wrote, displayed in a left-bordered card to visually distinguish it from the event details
4. **Event Details card** — A gray card showing:
* Event name
* Date and time with duration (e.g., "Saturday, March 7 at 9:00 AM - 10:30 AM (1h 30m)")
* Court/space assignment (if applicable)
5. **Footer** — Club name and OpenCourt branding
***
Where Else These Emails Appear [#where-else-these-emails-appear]
Admin-sent event emails are tracked across the platform:
| | Location & What you see |
| -------------------------------- | ---------------------------------------------------------------------------------- |
| **Event detail → Email Log tab** | All emails for this specific event (admin-sent + system notifications) |
| **Settings → Email History** | Shows with the label "Admin: Event Email" alongside all other sent emails |
| **User profile → Emails tab** | Visible per-user when viewing a specific member's email history in the admin panel |
***
Tips [#tips]
* **Use it for time-sensitive updates** — Court change, schedule shift, weather cancellation, parking info, or any detail that participants need to know before the event.
* **Uncheck waitlisted members** if the update only applies to confirmed participants (e.g., court assignments).
* **Check the Email Log** after sending to verify delivery. If any emails failed, you can see the error reason by hovering over the red status badge.
* **No setup required** — Unlike Email Campaigns, this feature works out of the box. It uses the platform's transactional email stream, so there's no club-level email configuration needed.
# Swish Integration - Effortless Game Management
Swish is a platform that makes it very easy for you to run leagues, tournaments, and a variety of other types of organized games, such as round robins, king of the court, etc.\
You can learn more about Swish [here](https://swishsportsapp.com/).
OpenCourt integrates with Swish seamlessly.
With OpenCourt+Swish, you can now create events and collect sign-ups on OpenCourt, then transition the participant list over to Swish in one click, so that you can run your game, league, or a tournament in Swish.
How to use Swish integration in OpenCourt [#how-to-use-swish-integration-in-opencourt]
In most cases, you’ll be synchronizing the participation list into Swish immediately before the game/league/tournament starts, when your participant list of confirmed and final.
1. In the OpenCourt admin panel, find and open the Event that you’re looking to sync.
2. Click on the Swish Sync button
3. The window may take a few seconds to load as it loads information from Swish. Once it’s loaded, choose the Game Type.
4. Depending on the game type, you’ll be presented with an appropriate screen to fill out any additional information and assign people to groups.
5. Click “Send to Swish” when you’re ready
6. Now you will find this game in your Club Account in the Swish App.
Remember, once the game is in Swish, you can still manage participants, their DUPR ids, and more – but now in the Swish App.
If you re-sync the game into Swish, please note **all participants will be replaces with new participants**.
How to integrate Swish with OpenCourt [#how-to-integrate-swish-with-opencourt]
1. Make sure you have a Swish Club account. If you don’t have one yet, reach out to [clubs@swishsportsapp.com](mailto:clubs@swishsportsapp.com).
2. Log in to the Swish Club Portal:
[https://club.swishsportsapp.com/](https://club.swishsportsapp.com/club-profile).
3. Copy the API Key listed in the `API Access` Section.
4. Send this API Key to your OpenCourt representative, or over to [club-support@getopencourt.com](mailto:club-support@getopencourt.com).
5. Your OpenCourt representative will activate the integration on your account and will inform you when it’s ready to be used.
Questions? [#questions]
Please reach out to OpenCourt at [club-support@getopencourt.com](mailto:club-support@getopencourt.com) or to Swish at [clubs@swishsportsapp.com](mailto:clubs@swishsportsapp.com) for any additional support.
# Creating and Editing Memberships
Before creating a membership, make sure you understand the what Memberships and Rule Sets are, and the relationship between them: [read here](/help/facility-operators/memberships-and-rule-sets/memberships-and-rule-sets-overview).
Creating a New Membership [#creating-a-new-membership]
1. Go to **Admin →** **Memberships**.
2. Click **New Membership**.
3. Enter the **Membership Name**.
Once created, you’ll be taken to the membership settings page where you can configure everything below.
***
Membership Name & Description [#membership-name--description]
* **Name** — displayed to customers on the memberships page and at checkout
* **Description** — supports [Markdown formatting](https://www.markdownguide.org/cheat-sheet/). Use it to list benefits, included perks, or anything that helps customers understand the value. Start each line with a hyphen (`-`) for bullet points
Your future members will see it like this:
***
Assigning a Rule Set [#assigning-a-rule-set]
Every membership must be linked to exactly one Rule Set, which controls court booking rates, advance booking windows, schedule visibility, and refund policy. Select a rule set from the dropdown under Membership Rule Set.
If your club doesn’t have any rule sets yet, one will be created automatically with default settings. You can edit it later from Admin → Membership Rule Sets.
→ See \[Creating and Managing Rule Sets] for details on configuring rule sets.
***
Display membership publicly or keep them Admin-only [#display-membership-publicly-or-keep-them-admin-only]
Click **Settings & Plans** tab.
* Toggle **List on Home Page** ON to make the membership visible and purchasable by users from the Home Page → Memberships page ([app.getopencourt.com](https://app.getopencourt.com/) or app).
* Toggle it OFF to make the membership **admin-only** (users won’t see it on the [website](https://app.getopencourt.com/) or app).
Admin-only memberships are useful for:
* Corporate or business agreements
* Special pricing for specific users
* Private offers or promotions
***
Displaying Pricing Publicly [#displaying-pricing-publicly]
* You can choose to display on the Memberships Page:
* All pricing plans
* Only selected plans
* If a plan is **active but not displayed publicly**:
* Users cannot purchase it themselves
**Admins can still assign it manually.**
Example:\
Promo Plan with 20% discount is not displayed publicly, so your future members can’t purchase it on the website or in the app.
Your customer’s view:
But admins can [sell it via the admin portal](/help/facility-operators/customers-and-families/selling-a-membership-to-customers):
If a plan is **inactive**:
* It cannot be sold or assigned anymore
* Existing members on that plan remain and continue renewing
This is useful for:
* Early-bird pricing (example: you have a special price before club opening, then these members keep the discounted plan, but no one else can buy it anymore).
* Limited-time offers
* Legacy plans
***
Archiving a Membership [#archiving-a-membership]
If a membership is no longer offered but has existing members, you can **archive** it.
1. Go to **Admin → Memberships → \[membership] → Settings**
2. Scroll to the bottom and click **Archive**
3. Confirm by typing the membership name
Archived memberships are hidden from new sign-ups, but existing members keep their access and billing continues as normal. You can **unarchive** at any time to make it available again.
***
Deleting a Membership [#deleting-a-membership]
A membership can only be deleted if it has **never** had any members (current or past). If it has, use Archive instead.
To delete: go to **Settings**, scroll to the bottom, and click **Delete**. Confirm by typing the membership name.
***
Reordering Memberships [#reordering-memberships]
Drag and drop memberships on the Admin → Memberships list to change the order they appear on the public memberships page.
***
What’s Next [#whats-next]
* **[Setting Up Plans & Pricing →](/help/facility-operators/memberships-and-rule-sets/setting-up-membership-plans-and-pricing)** Add billing plans — monthly, annual, one-time, or free
* **[Family & Dependent Memberships →](/help/facility-operators/memberships-and-rule-sets/family-and-group-memberships)** Enable group memberships with dependent members
* **[Selling a Membership to a Customer →](/help/facility-operators/customers-and-families/selling-a-membership-to-customers)** Enroll a customer from the admin panel
# Creating and Managing Rule Sets
***
| Layer | What it controls | Where it lives |
| ----------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------- |
| **Membership settings** | Name, description, pricing tiers, visibility, family/group config | Admin → Memberships → \[membership] → Settings |
| **Rule set** | Court booking rates, schedule visibility, booking advance limits, refund policy | Admin → Settings → Membership Rule Sets → \[rule set] |
What is a Rule Set? [#what-is-a-rule-set]
A rule set is a named configuration profile that controls how members book courts. It has four areas:
1. **Pricing** — court booking rates (hourly, per-person, daily), including time- or day-based overrides
2. **Schedule** — how far into the future members can see the court schedule
3. **Reservations** — how far in advance members can book, default booking duration, cancellation window
4. **Refunds** — cancellation refund percentages and non-refundable periods
Rule sets exist separately from memberships so a single configuration can be reused across multiple membership products (e.g., "Standard Member" and "Family Standard Member" may share the same rule set if their booking privileges are identical).
One special rule set is always present and cannot be deleted:
* **Non-Member** — applied to logged-in users with no active membership
Creating a rule set [#creating-a-rule-set]
1. Go to **Memberships → Rule Sets**
2. Click **+ New Rule Set**
1. Fill in:
* **Name** (required) — identifies the rule set in dropdowns throughout the admin
* **Description** (optional) — internal notes, not shown to members
* **Default** — check this if new memberships should default to this rule set
2. Click **Create**
You are redirected to the rule set settings page where you can configure all four tabs.
Editing a rule set [#editing-a-rule-set]
1. Go to **Memberships → Rule Sets**
2. Click the rule set name in the list
3. Make changes across the four tabs:
Court Booking Rates tab [#court-booking-rates-tab]
Defines the cost applied when a member books a court.
**Basic mode** — a single default rate that applies to all courts, all times:
* **Court hourly** — per-court hourly charge
* **Person hourly** — per-person hourly charge
* **Person daily** — per-person daily cap
* **Person fixed** — flat per-person fee per booking
[Learn more about pricing models here](/help/facility-operators/pricing-and-discounts/pricing-models).
**Advanced mode** — You can set the combination of the previous models. E.g. Daily fee for guests in addition to the court hourly price.
If you want to charge members a guest fee, make sure to check the box **“Set custom pricing for other court booking participants”** and enter the fee. This is usually set either **per person, per hour** or as a **fixed fee per person, per reservation**.
**Add an override rule**
Click **+ Add Rule**. A dialog opens with the following fields:
* **Rule name** — give it a descriptive label, e.g., `Off-Peak Hours`
* **Days** — select the days this rule applies to. Toggle individual days (Mon–Sun) or click **All** to select every day. For weekday mornings, select Mon, Tue, Wed, Thu, Fri.
* **Time** — choose **Specific times**, then set the start and end time (e.g., 6:00 AM – 11:00 AM). Times are in 30-minute increments. You can add multiple time ranges per rule by clicking **Add another time frame**.
* **Courts** — select specific courts this rule applies to, or click **All** to apply it to every court.
* **Pricing mode** — select the pricing mode that matches your default (e.g., **Court/Space fee, per hour**), then enter `30` in the **Court hourly** field.
Click **Create Rule**.
Schedule tab [#schedule-tab]
Controls what members see on the schedule page:
* **Can see schedule** — toggle to allow/block access to the schedule entirely
* **Rolling hours** — show only the next N hours of availability
* **By calendar day** — show availability up to N calendar days ahead
* Release time settings (when a future day first becomes visible)
Reservations tab [#reservations-tab]
Controls booking creation:
* **Can create reservations** — toggle to allow/block booking
* **Advance booking limit** — how far ahead a member can book:
* Unlimited
* Fixed hours (e.g., 72 hours in advance)
* Fixed calendar days (e.g., 7 days in advance)
* **Default booking duration** — pre-selected length when opening the booking dialog (30–300 minutes)
* **Allow court overlap** — whether a member can hold overlapping reservations
* **Cancellation window** — minimum hours before a booking that cancellation is allowed
Refunds tab [#refunds-tab]
Defines the refund policy when a booking is canceled:
* Percentage refunded based on how far in advance the cancellation happens
* Non-refundable period (e.g., no refund within 2 hours of the booking)
Changing which rule set a membership uses [#changing-which-rule-set-a-membership-uses]
1. Go to **Admin → Memberships → \[membership] → Settings**
2. Scroll to the **Membership Rule Set** section
3. Select a different rule set from the dropdown
4. Click **Save changes**
All existing members are immediately subject to the new rule set's booking configuration on their next booking attempt.
# Family & Group memberships
Families vs. Family Memberships — Two Different Things [#families-vs-family-memberships--two-different-things]
OpenCourt has two related but separate concepts:
**A Family** is a group of related people on the platform — a parent and their children, a couple, a household. Families are useful on their own, without any membership at all: family members can sign each other up for events, programs, and clinics, and manage bookings on behalf of their relatives and children.
**A Family Membership** is a billing arrangement built on top of a family. One person (the Primary Member) pays for a membership, and other family members (dependents) are automatically enrolled in a dependent membership at no additional cost.
You can have families without a family membership. You cannot have a family membership without a family.
| | Family (no membership) | Family + Family Membership |
| ----------------------------------------------- | ---------------------- | -------------------------------------- |
| Sign up relatives for events | Yes | Yes |
| Manage bookings for children | Yes | Yes |
| Primary member pays for others’ membership | N/A | Yes |
| Dependents get their own booking rates & access | N/A | Yes, via dependent membership rule set |
→ *To create a family and add members, see \[Creating and Managing a Family Account]. The rest of this article covers how to set up the membership product that applies to families.*
***
How Family Memberships Work [#how-family-memberships-work]
A family membership has two parts:
1. **The primary membership** — a regular membership that the Primary Member of a family purchases and pays for
2. **The dependent membership** — a separate, automatically created membership that gets assigned to other family members at no cost
Each has its own **rule set**, so the primary member and dependents can have completely different booking rates, advance booking windows, and schedule access.
Setting Up a Family Membership [#setting-up-a-family-membership]
1. Go to **Admin → Memberships → \[membership] → Settings**
2. Toggle **Family / Group Membership** on
3. Set **Maximum family members** (minimum 2; leave empty for unlimited)
4. Click on “Create Dependent Membership” if one doesn’t exist yet
OpenCourt creates a dependent membership linked to this one. You’ll see it appear in your memberships list.
Configuring the Dependent Membership’s Rule Set [#configuring-the-dependent-memberships-rule-set]
By default, the dependent membership uses the same rule set as the primary. You can assign a different one — for example:
* Primary “Family Premium” membership → “Premium Member” rule set ($15/hr rates, 14-day advance booking)
* Dependent membership → “Junior Member” rule set ($10/hr rates, 3-day advance booking)
To change: go to the dependent membership’s settings and select a different rule set from the dropdown.
What Happens When the Primary Membership Changes [#what-happens-when-the-primary-membership-changes]
| Primary Member Action | Effect on Dependents |
| ------------------------ | -------------------------------------------------------------------------------- |
| Cancels or is terminated | All dependents lose access immediately |
| Membership expires | All dependents expire on the same date |
| Membership is frozen | Dependents are also frozen — no membership benefits until the primary is resumed |
Limits [#limits]
* Each membership can have **one** dependent membership product
* A user who is already a dependent in a family **cannot** purchase their own subscription at the same club
Related Articles [#related-articles]
* **[Creating and Managing a Family Account →](/help/facility-operators/customers-and-families/creating-and-managing-a-family-account)** Set up a family group, add a primary member and dependents — with or without a membership
* **[Selling a Membership to a Customer →](/help/facility-operators/customers-and-families/selling-a-membership-to-customers)** How to enroll the primary member and assign dependent memberships
***
# Memberships and Rule Sets
Memberships are what you sell; rule sets decide what each customer may book and at what price. Read the overview first, then set up plans, pricing and rule sets.
Articles [#articles]
* [Memberships & Rule Sets – Overview](/help/facility-operators/memberships-and-rule-sets/memberships-and-rule-sets-overview) — Memberships let you create and sell recurring or one-time plans to your customers.
* [Creating and Editing Memberships](/help/facility-operators/memberships-and-rule-sets/creating-and-editing-memberships)
* [Setting Up Membership Plans & Pricing](/help/facility-operators/memberships-and-rule-sets/setting-up-membership-plans-and-pricing) — Each membership can have multiple pricing plans — different ways for customers to pay for the same membership.
* [Creating and Managing Rule Sets](/help/facility-operators/memberships-and-rule-sets/creating-and-managing-rule-sets) — Memberships in OpenCourt have two distinct layers of configuration: Membership settings and Rule Sets.
* [Run a membership presale](/help/facility-operators/memberships-and-rule-sets/run-a-membership-presale) — Collect early signups, with an optional presale fee or deposit, before a membership goes live.
* [Family & Group memberships](/help/facility-operators/memberships-and-rule-sets/family-and-group-memberships)
# Memberships & Rule Sets – Overview
**Memberships let you create and sell recurring or one-time plans to your customers. Rule Sets control what members can do — court/bay/space booking rates, how far in advance they can book, schedule visibility, and refund policies.**
Every membership is linked to exactly one rule set. The membership defines *who pays what* (name, pricing plans, billing). The rule set defines *what they get* (booking rates, access rules, refund windows). This separation lets you offer different membership products — say, an Individual and a Family plan — that share the same booking privileges, without configuring those rules twice.
Example: A club offers three memberships — Individual ($99/mo), Couple ($149/mo), and Family ($199/mo). All three (and their dependents) are linked to the same “Standard Member” rule set, which gives members $20/hr court rates, 7-day advance booking, and full refunds up to 24 hours before a booking.
| Layer | What it controls | Where it lives |
| ----------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------- |
| **Membership settings** | Name, description, pricing tiers, visibility, family/group config | Admin → Memberships → \[membership] → Settings |
| **Rule set** | Court booking rates, schedule visibility, booking advance limits, refund policy | Admin → Settings → Membership Rule Sets → \[rule set] |
A note on terminology [#a-note-on-terminology]
In this help center, we use **“creating a membership”** to mean building the membership product (name, plans, pricing). When a membership is **sold or assigned** to a customer, we say “selling” or “assigning” a membership. This distinction matters because the setup workflow (done once) is different from the day-to-day workflow of enrolling customers.
Non-members and guests [#non-members-and-guests]
OpenCourt also has a built-in **Non-Member** rule set that applies to logged-in users who don’t hold any active membership. This lets you set default court rates and booking rules for walk-in or pay-per-play customers without creating a membership for them.
What to read next [#what-to-read-next]
* **[Creating a Membership →](/help/facility-operators/memberships-and-rule-sets/creating-and-editing-memberships)** Set up a new membership with name, description, and visibility
* **[Setting Up Plans & Pricing →](/help/facility-operators/memberships-and-rule-sets/setting-up-membership-plans-and-pricing)** Add billing plans — recurring, one-time, or free
* **[Creating and Managing Rule Sets →](/help/facility-operators/memberships-and-rule-sets/creating-and-managing-rule-sets)** Configure court rates, booking windows, and refund policies
* **[Selling a Membership to a Customer →](/help/facility-operators/customers-and-families/selling-a-membership-to-customers)** Assign or sell a membership from the admin panel
# Run a membership presale
Open memberships for signup before your club opens, take an optional presale fee or deposit, and turn each signup
into a real membership when you're ready. *(About 15 minutes to set up. You need your memberships created first.)*
Presales live under **Membership Presale** in your admin sidebar. You need the **Memberships & Subscriptions**
permission to run one. Turning presales on for your club also needs **Rule Sets (Booking Rates & Rules)**.
Before you begin [#before-you-begin]
* **Your memberships already exist**, each with at least one pricing plan. A presale sells plans you have already
created — see [Setting Up Membership Plans & Pricing](/help/facility-operators/memberships-and-rule-sets/setting-up-membership-plans-and-pricing).
* **To charge a presale fee, your club accepts card payments.** A free presale collects a card but charges nothing.
Turn on Membership Presale in your sidebar [#turn-on-membership-presale-in-your-sidebar]
**Membership Presale** is hidden until you switch it on.
1. Go to **Memberships → Settings**.
2. Under **Menu Visibility**, turn on **Show Membership Presale in sidebar**.
3. Click **Save Changes** at the bottom of the page.
**Membership Presale** now appears in your sidebar.
Add memberships to your presale [#add-memberships-to-your-presale]
1. Go to **Membership Presale**, then open the **Presale Settings** tab.
2. Click **Add memberships**.
3. Tick each pricing plan you want to offer.
4. Enter a **Presale Fee** for each ticked plan. This is what the customer pays when they sign up. Enter *0* for a
free presale.
5. Click **Add**.
Your plans appear in the table, grouped by membership.
To change a fee later, click the pencil next to it. The new fee applies to new signups only — customers who already
signed up keep what they paid.
Add a confirmation note to a plan [#add-a-confirmation-note-to-a-plan]
A confirmation note is one sentence customers see after they sign up for that plan. Use it for anything you have
promised on top of the price, such as *"Your $100 deposit is credited to your first month."*
Each plan has its own note, so a founding-member offer and a standard plan can say different things.
1. In the plan's row, click the note icon in **Actions**.
2. Type your note.
3. Click **Save note**.
The icon turns green, and the note shows under the plan's name in the table. Customers see it on their confirmation
screen, on your club's **Memberships** page, and in their presale confirmation email.
To take a note off, open it again and click **Remove note**.
Open the presale to customers [#open-the-presale-to-customers]
* **Presale is live** at the top of **Presale Settings** is the master switch. When it is off, customers cannot see or
sign up for any presale plan.
* The **Active** switch in each row shows or hides that one plan.
* To share a plan directly, click the link icon in **Actions**. The presale link is copied to your clipboard.
* To change the order customers see, click **Reorder**, drag memberships and plans into place, then click
**Save Order**.
To take a plan out of the presale, click the delete icon in **Actions**. Its existing signups are kept.
What your customers see [#what-your-customers-see]
Presale plans appear on your club's **Memberships** page, each marked **PRESALE**.
When a customer opens a plan, they see what they will be charged now and what the membership costs after that.
* For a plan with a presale fee, they tap **Register and Pay**, add a card, then tap **Pay**.
* For a free presale, they tap **Register**, add a card, then tap **Submit**. The card is saved, not charged.
Once they have signed up, a confirmation screen shows **What you paid**, including your note for that plan, and
**Your membership**, with a line saying they won't be charged for the membership until you activate it.
Customers also receive a presale confirmation email and, for a paid presale, a receipt. Their signup stays visible
under **Your Reservations** on your **Memberships** page until they have an active membership.
A customer can cancel their own signup from their confirmation screen or the **Memberships** page. Their payment is
**not** refunded automatically — they are told to contact you.
Manage your signups [#manage-your-signups]
The **Signups** tab lists everyone who signed up. Filter by status or by membership, search the list, or use the
**Export** button to download it.
Each row has three actions:
| Icon | What it does |
| ------------------------- | ---------------------------------------------------- |
| **View customer profile** | Opens the customer's profile. |
| **Assign membership** | Starts their real membership — see the next section. |
| **Cancel presale signup** | Cancels the signup. |
When you cancel a signup, you choose whether to **Issue refund** (paid signups only) and whether to **Send customer
an email**. A refund receipt is emailed separately.
Turn a signup into a membership [#turn-a-signup-into-a-membership]
When you're ready to open, start each customer's membership from their signup.
1. On the **Signups** tab, click **Assign membership** in the customer's row.
**Create Subscription** opens with the customer, the membership and the plan they signed up for already filled in.
2. Under **Subscription starts**, choose when their membership benefits begin.
3. Under **First payment**, choose when their first charge happens.
To credit a presale deposit against their first period, choose *Custom date* and set **Charge on** to one
billing period after the start date.
4. Choose the **Payment method** to charge. The card the customer used for their presale is listed as a saved card.
5. Click **Start Checkout**.
Their membership now shows under **Current membership** on the **Signups** tab.
You don't need to cancel the presale signup afterwards — **Current membership** already shows who you have
converted. Cancelling it would send the customer a cancellation notice unless you untick **Send customer an email**.
For more on the **Create Subscription** page, see [Selling a membership to customers](/help/facility-operators/customers-and-families/selling-a-membership-to-customers).
If something goes wrong [#if-something-goes-wrong]
* **Membership Presale isn't in your sidebar** — check these in order:
1. **The switch is off.** Turn on **Show Membership Presale in sidebar** under **Memberships → Settings**. It
applies to your whole club, so another admin may already have turned it on.
2. **Your role is missing a permission.** The sidebar item needs **Memberships & Subscriptions**, and opening
**Memberships → Settings** needs **Rule Sets (Booking Rates & Rules)**. Ask an admin who manages your team under
**Settings → Admin Team** to add them to your role.
3. **Presales aren't available for your club yet.** If an admin with both permissions sees no **Menu Visibility**
section under **Memberships → Settings**, contact support.
* **Customers can't see a presale plan** — check that **Presale is live** is on and the plan's **Active** switch is
on. A plan marked **Plan archived** is hidden from customers: restore it in your membership catalog, or remove it
from the presale.
* **A plan is missing from Add memberships** — it is already in your presale, or it doesn't exist yet. Create it
under **Memberships → Catalog** first.
* **A customer cancelled and wants a refund** — cancelling doesn't refund them. Refund the payment from **Orders &
Transactions** — see [Processing refunds](/help/facility-operators/pricing-and-discounts/processing-refunds).
* **Existing signups show an old presale fee** — fee changes apply to new signups only. Each customer keeps the amount
they paid.
* **A customer didn't get your note by email** — the confirmation email goes out when they sign up. A note added
later shows on their confirmation screen and **Memberships** page, but not in an email they already received.
Related [#related]
* [Memberships and Rule Sets](/help/facility-operators/memberships-and-rule-sets)
* [Setting Up Membership Plans & Pricing](/help/facility-operators/memberships-and-rule-sets/setting-up-membership-plans-and-pricing)
* [Selling a membership to customers](/help/facility-operators/customers-and-families/selling-a-membership-to-customers)
* [Processing refunds](/help/facility-operators/pricing-and-discounts/processing-refunds)
# Setting Up Membership Plans & Pricing
Each membership can have multiple **pricing plans** — different ways for customers to pay for the same membership. For example, a single membership might offer a Monthly plan, an Annual plan, and an Early Bird promotional plan.
Adding a Plan [#adding-a-plan]
1. Go to **Admin → Memberships → \[membership] → Settings**
2. Scroll to **Pricing Plans**
3. Click **Add Plan**
4. Fill in:
* **Name** — what the customer sees (e.g., “Annual Plan”, “Monthly Plan”)
* **Price** — the billing amount
* **Duration** — billing interval in months (e.g., 1 for monthly, 12 for annual)
* **Initiation fee** *(optional)* — a one-time fee charged at sign-up in addition to the first billing period
* **Description** *(optional)* — additional detail shown to customers during checkout
5. Save
| Type | How to set it up | Billing behavior |
| --------- | -------------------------- | ----------------------------------------------------------------------------------- |
| Recurring | Set a price and duration | Charges automatically every billing cycle until canceled |
| One-time | Toggle One-time payment on | Charges once; membership expires at the end of the duration, no auto-renewal |
| Free | Toggle Free membership on | No charge; useful for trial memberships, staff memberships, or complimentary access |
Make sure to set the correct billing interval (for example, 12 months for annual plans).
Active vs. Displayed [#active-vs-displayed]
Each plan has two independent toggles:
* **Active** — whether the plan can be sold at all
* *Active:* can be purchased by customers or assigned by admins
* *Inactive:* cannot be sold or assigned to new members. Existing members on this plan continue as normal
* **Displayed publicly** — whether the plan appears on the public memberships page
* *Displayed:* customers can see and purchase it
* *Hidden:* only admins can sell or assign it
This gives you four combinations:
| | Displayed | Hidden |
| -------- | ----------------------------------------------- | --------------------------------------------- |
| Active | Customer self-service + admin | Admin-only (corporate deals, special pricing) |
| Inactive | (not possible — inactive plans are auto-hidden) | Legacy plan, existing members only |
Direct Purchase Links [#direct-purchase-links]
Every plan has a **direct purchase link** that you can copy and share. This works even for hidden plans — useful for sending a private sign-up link to a specific customer or group without listing the plan publicly.
To copy: click the **link icon** next to the plan on the Settings page.
Promotional Text [#promotional-text]
Use the **Promo text** field to add a promotional label that appears on the membership listing (e.g., “Most Popular”, “Save 20%”). This supports strikethrough formatting using `~~text~~` — for example, `~~$149~~ $99` renders as ~~$149~~ $99.
Reordering Plans [#reordering-plans]
Drag and drop plans to change the order they appear to customers on the membership page and at checkout.
Deleting a Plan [#deleting-a-plan]
A plan can only be deleted if **no members** have ever purchased or had it. If members exist or have existed in the past, deactivate it instead — existing members keep their billing, but no new members can be added.
See [Selling a membership to customers](/help/facility-operators/customers-and-families/selling-a-membership-to-customers) for how to enroll customers on a specific plan.
# Payment Processing & Payouts
How OpenCourt and Stripe move money from your customers to your bank account, and what the statuses in your Stripe dashboard mean.
Articles [#articles]
* [OpenCourt + Stripe Integration](/help/facility-operators/payments-and-payouts/opencourt-stripe-integration) — OpenCourt uses Stripe to allow you to collect the payments from your customers for things like court reservations, event signups, memberships, POS.
* [Payment Settlement & Revenue Disbursement](/help/facility-operators/payments-and-payouts/payment-settlement-and-revenue-disbursement) — OpenCourt does not collect or hold any funds we process on your behalf.
* [Why Do I See "Incomplete" Payments in My Stripe Dashboard?](/help/facility-operators/payments-and-payouts/why-do-i-see-incomplete-payments-in-my-stripe-dashboard) — If you've noticed a number of payments marked as "Incomplete" in your Stripe dashboard, don't worry — this is completely normal and does not indicate any issue with your account, your customers, or OpenCourt.
# OpenCourt + Stripe Integration
OpenCourt uses Stripe to allow you to collect the payments from your customers for things like court reservations, event signups, memberships, POS.
Stripe is a leading online and in-person payment processor that’s used by millions of businesses on their websites and applications. We choose it because it’s extremely reliable, has amazing customer support, and it supports the vast variety of payment types OpenCourt processes for you on the platform. You can learn more about Stripe [here](https://stripe.com/).
OpenCourt does not directly process transactions through itself. OpenCourt doesn’t hold any of your funds; all payments processed through OpenCourt go directly to your Stripe account, and from there to your bank account. OpenCourt is simply a facilitator and authorizes transactions on the behalf of your Stripe account. Your customers will see your business name on their credit card statement, not OpenCourt.
Stripe pricing is very similar to most payment processors. There’s no monthly fee; stripe takes a small portion of each payment processed through it. **No matter what payment processor you use, if you process transactions, you WILL end up paying such fee.** Stripe keeps some of that fee, the rest of the fee goes to the banks involved in the transactions and the payment network, such as Visa/MC/Amex. Whether you use OpenCourt or any other platform, a payment processor is involved behind the scenes and the payment processing fees will be collected from the revenue you collect.
Stripe fees are listed [here](https://stripe.com/pricing). The fees are lower for in-person transactions via the terminal, and slightly higher for online transactions. They’re generally inline with other online payment processors.
Payment processing fees are generally considered a cost of doing business – and you’ll generally make significantly more revenue if you accept credit cards compared to the amount of fees you’ll pay. That said, if you’re a business that’ll be processing a high volume of transactions, you can negotiate custom pricing with Stripe, including IC+ pricing.
Your Stripe account is exactly that: it’s ***yours***. While OpenCourt team will often help set it up, we don’t and can’t manage your Stripe account. It is your responsibility to set up your Stripe settings such as Payouts so you can receive disbursements into your bank account.
**Do NOT turn on Stripe Tax (stripe’s paid service to calculate and apply sales tax) when using Stripe with OpenCourt.** OpenCourt calculates, applies, and keeps track of your sales tax automatically. Turning on Stripe Tax will result in sales tax double-charged in certain situations.
You will often want to give your accountant limited (read-only) access to your Stripe account so that they can run reconciliation reports.
# Payment Settlement & Revenue Disbursement
OpenCourt does not collect or hold any funds we process on your behalf. When we charge a customer, we do it on behalf of your Stripe account, and all funds go straight into your Stripe account.
You can learn more about our integration with Stripe [in this article](/help/facility-operators/payments-and-payouts/opencourt-stripe-integration).
Make sure to enable Payouts in Stripe, specify your business information and your business checking account which will be receiving payouts. You might also choose frequently of distributions (daily, weekly, etc), or keep it manual.
Payments are typically settled within 1-2 business days. Payouts are often processed within 1-2 days from that. Payouts are bundled together from which ever payments are settled by the time the payout is processed.
Your first payout might take \~7 days to be processed.
Make sure to monitor your Stripe account if you feel like you aren’t receiving your first payouts or any further payouts. Stripe’s support team is amazing, so always feel free to contact them via their [support center](https://support.stripe.com/).
# Why Do I See "Incomplete" Payments in My Stripe Dashboard?
What's happening? [#whats-happening]
When a customer visits a checkout page on your OpenCourt site — whether they're purchasing a membership, buying a booking pass, or paying for a court reservation — Stripe requires OpenCourt to create something called a **Payment Intent** before the payment form can even be displayed.
Think of a Payment Intent as a placeholder. It tells Stripe: "A customer is about to pay this amount." At this stage, no money has been charged.
If the customer completes the payment, the Payment Intent is confirmed and you'll see a **"Succeeded"** status in Stripe. But if the customer leaves the page without finishing — maybe they got distracted, changed their mind, or just closed the browser tab — the Payment Intent stays behind with an **"Incomplete"** status.
**Every platform that uses Stripe's modern payment form works this way.** It is not unique to OpenCourt.
Are my customers being charged? [#are-my-customers-being-charged]
**No.** Incomplete payments mean that no charge was made. No money left the customer's account. These are simply records of payment forms that were displayed but never submitted.
Will these clean up on their own? [#will-these-clean-up-on-their-own]
Incomplete Payment Intents will remain on your Stripe dashboard unless you manually cancel them. However, they are harmless — they don't affect your balance, your payouts, or your customers in any way. They are simply records of payment forms that were opened but never completed.
For incomplete subscriptions specifically, Stripe itself automatically expires them after 23 hours if the first invoice is never paid. These will show as **"Incomplete Expired"** or **"Cancelled"** in your dashboard, which is also normal.
Can I filter them out? [#can-i-filter-them-out]
Absolutely. In your Stripe dashboard, instead of viewing **"All"** payments, use the **"Succeeded"** filter to see only completed, successful transactions. This gives you a clean view of actual revenue without the noise of incomplete entries.
What if I see the same customer with multiple incomplete entries? [#what-if-i-see-the-same-customer-with-multiple-incomplete-entries]
This can happen if a customer visits your checkout page more than once without completing the purchase. Each visit generates a new Payment Intent. You can manually cancel these in your Stripe dashboard if you'd like to keep things tidy.
Should I be concerned? [#should-i-be-concerned]
Not at all. Seeing incomplete payments is completely normal. Many of your customers are simply exploring — they might click through to see pricing, check availability, or browse membership options. Once they see the details, some will complete the purchase and others will move on. That's expected behavior, and every incomplete entry is just evidence of someone discovering what your facility has to offer.
If you have any questions, feel free to reach out to us at [**support@getopencourt.com**](mailto:support@getopencourt.com).
# Adding products
Step-by-Step: Creating a Product [#step-by-step-creating-a-product]
1. **Go to the Products Tab**
* From your admin dashboard, navigate to **“Products”** tab
* Click **“Create New Product.”**
2. **Fill in Product Details**
* **Name**: This is the product name your customers will see (e.g., *Paddle*).
* **Category**: Assign the product to an existing category (e.g. *Gear*)
* [**Manage categories separately**](/help/facility-operators/point-of-sale/managing-categories) (below)
* **Price**: Set the retail price for the product.
* **Sales Tax**: (*optional*) You can change to a custom tax rate. Otherwise, the default club tax will be applied.
* **Quantity** *(optional)*: Use this if you want to track inventory.
* **Description** *(optional)*: Appears on the payment page if selling via link.
3. **Activate the Payment Link (Optional)**
* Turn this on if you want people to be able to buy the product via a direct link or QR code.
* After activation, you’ll be able to:
* **Copy the product link** - you can send it to a customer, they can pay from their phone
* **Download or print a QR code** - a customer can scan it, and pay from they phone
4. Save the product
5. Once all required fields are completed, save the product. It will now appear in your All Products list.
***
📁 Managing Categories [#-managing-categories]
* Go to **Products** tab **> Manage Categories** to add, rename, or delete categories.
* You **cannot delete** a category if it still has products assigned to it.
***
Tips [#tips]
* Descriptions are helpful for customer clarity.
* You can always come back and edit a product later.
# Connecting POS Terminal
Connecting the Stripe terminal is a 3-step process:
1. Generate the pairing code generated on the terminal (done by you)
2. Enter that pairing code into the Stripe admin panel (done by you or by OC)
3. Connect the resulting terminal ID in to the OpenCourt system (done by OC)
1. Generate the pairing code generated on the terminal [#1-generate-the-pairing-code-generated-on-the-terminal]
1. To open the settings menu, **swipe right from the left edge of the reader screen** to reveal a **Settings** button. Tap the **Settings** button and enter the admin PIN `07139`.
2. Tap **Generate pairing code**.
2. Enter that pairing code into the Stripe admin panel [#2-enter-that-pairing-code-into-the-stripe-admin-panel]
1. In your Stripe admin panel, open the [Readers](https://dashboard.stripe.com/terminal/readers) page, click **Register reader**.
2. Enter the pairing code code from the above then click **Next**.
3. Optionally, choose a name for the reader.
4. If you already created a Location, select the reader’s new Location. Otherwise, create a Location by clicking **+ Add new**. Name of the location doesn't matter.
5. Click **Register** to finish registering your reader.
6. Let your OpenCourt representative know the above is done.
3. Connect the resulting terminal ID in to the OpenCourt system [#3-connect-the-resulting-terminal-id-in-to-the-opencourt-system]
Contact your OpenCourt representative, we will do this for you.
After everything is set up, **Terminal** will show up as a payment processing option for every transaction you process from the admin panel.
# POS & Products
Sell gear, merchandise, gift cards and other items through OpenCourt, and take in-person payments with a Stripe terminal.
Articles [#articles]
* [Purchasing POS Terminal](/help/facility-operators/point-of-sale/purchasing-pos-terminal) — In order to accept in-person payments, you need to purchase a Point-of-Sale terminal.
* [Connecting POS Terminal](/help/facility-operators/point-of-sale/connecting-pos-terminal)
* [Adding products](/help/facility-operators/point-of-sale/adding-products) — You can sell gear, merchandise, or any other items directly through OpenCourt.
* [Managing Categories](/help/facility-operators/point-of-sale/managing-categories) — You can easily organize your products in OpenCourt by creating categories such as Beverages, Merch, or Gear.
* [Sell and manage gift cards](/help/facility-operators/point-of-sale/sell-and-manage-gift-cards) — Sell digital gift cards online and at the front desk, and give free ones.
# Managing Categories
🛠 Step 1: Go to the Products Page [#-step-1-go-to-the-products-page]
1. From the left-hand menu, click **Products**.
2. You’ll see three tabs at the top of the page.
🗂 Step 2: Add a New Category [#-step-2-add-a-new-category]
1. Click the **Manage Categories** tab.
2. Click the **Add New Category** button.
3. Enter the name of your new category (e.g., *Beverages*, *Merch*, *Gear*).
4. Click **Submit**.
You can create as many categories as needed to organize your items (e.g., *Branded T-Shirts* under **Merch**, or *Paddles* under **Gear**).
To [add products](/help/facility-operators/point-of-sale/adding-products) by some category follow instructions [here](/help/facility-operators/point-of-sale/adding-products).
You can also delete or edit categories by clicking corresponding icon
# Purchasing POS Terminal
In order to accept in-person payments, you need to purchase a Point-of-Sale terminal. We integrate with terminals sold by Stripe.
In-person payments might be more convenient, and they come with a lower payment processing fee compared to online payments. You can learn about Stripe processing fees here: [https://stripe.com/pricing](https://stripe.com/pricing)
**Terminals can be purchased here:** [**https://stripe.com/terminal/devices**](https://stripe.com/terminal/devices)
Stripe Reader S710, S700, and BBPOS WisePOS E are the terminals that are supported by OpenCourt. Note that S710 might not yet be available for sale. As of writing this article, pricing ranges between $249-349. It’s a one-time fee, no further fees are applied for using the terminal. You will need to log in to your Stripe account in order to order the terminal.
POS terminals require reliable wi-fi connection, so make sure you have a wi-fi access point where the terminal will be located.
OpenCourt supports connecting multiple terminals, if you need to have them at multiple places at your club (eg: bar, front desk, etc).
Allow some time for shipping.
Once you receive the terminal, follow the instructions in the [Connecting POS Terminal](/help/facility-operators/point-of-sale/connecting-pos-terminal) article.
# Sell and manage gift cards
Customers buy a gift card for someone else, online or at your front desk. When the recipient redeems it, the full value goes into their club credit, which they spend at your club. *(About 10 minutes to set up. OpenCourt turns gift cards on for your club first.)*
Gift cards live under **Gift cards** in the admin menu. You need the **Gift Cards** permission to see the section. Selling a gift card at the POS needs the **Products & POS** permission.
How gift cards work [#how-gift-cards-work]
* Customers pay by card online. At the front desk, you take card or cash.
* The recipient gets an email with a link and a code.
* When the recipient claims the card, the **whole value** goes into their [club credit](/help/facility-operators/customers-and-families/club-credit) at your club. They spend it on bookings, events or products.
* A claimed card is used up. No balance stays on the card.
* A card works only at the club that sold it.
* Customers can't buy a gift card with club credit.
Before you begin [#before-you-begin]
* Ask OpenCourt support to turn on gift cards for your club. Until then, the **Gift cards** menu item doesn't appear.
* Connect Stripe so you can take card payments. See [Payments & Payouts](/help/facility-operators/payments-and-payouts).
* If you want cards to expire, check your local rules first.
Set up your gift cards [#set-up-your-gift-cards]
1. Go to **Gift cards** and open the **Settings** tab.
2. Under **Denominations**, enter the amounts a customer can choose in the **Face value (credit)** column — for example *$25*, *$50* and *$100*. Click **Add denomination** to add more.
3. Optional: enter a **Sale price** to charge less than the face value. For example, the customer pays *$80* for *$100* of credit. Leave it blank to charge the face value.
4. Optional: turn on **Allow custom amount** to let customers type their own amount. Set a **Minimum** and a **Maximum**.
5. Optional: turn on **Cards expire** and enter the **Days until expiry**. By default, cards never expire.
6. Optional: under **Store image**, click **Upload image** to set the picture on the gift card tile in your online store. A square image works best.
7. Under **Designs**, choose the artwork buyers can pick. OpenCourt includes *Gift Card*, *Birthday*, *Thank You* and *Congrats*. Click **Upload custom design** to add your own. Click the eye icon to hide a design without deleting it.
8. Optional: add **Terms & conditions**. Buyers and recipients see them.
9. Click **Save settings**.
10. When you are ready to sell, turn on **Publish to store & POS** at the top of the page.
**Publish to store & POS** and **Store image** save as soon as you change them. Everything else saves only when you click **Save settings**.
How customers buy a gift card online [#how-customers-buy-a-gift-card-online]
After you publish, a gift card tile appears in your online store with the price **Choose amount**. The customer:
1. Picks an amount and a design.
2. Enters the recipient's name and email, or turns on **Send to myself**.
3. Adds an optional message.
4. Clicks **Continue to payment** and pays by card.
The recipient gets the email after the payment goes through. The buyer can see and resend the cards they sent under **My Profile → Club Credit**.
{/* 🖼️ Screenshot — _Online store, Buy a gift card page._ Show the amount choices, the design picker and the recipient fields. · Alt: "Buy a gift card page in the online store with amounts, designs and recipient fields" · Save as: public/help/point-of-sale/gift-card-store.webp */}
Sell a gift card at the front desk [#sell-a-gift-card-at-the-front-desk]
1. Open the **POS**.
2. In the **Shopping cart**, click **+ Gift Card**.
3. Pick an **Amount** and a **Design**.
4. Enter a **Recipient email** to email the card to the recipient. Leave it blank to give the code to the buyer yourself.
5. Optional: add a **Recipient name** and a **Message**.
6. Optional: turn on **Expires** to change the expiry for this card. It starts with your club's expiry setting.
7. Set the **Quantity** to sell several identical cards at once.
8. Click **Add card**, then take payment as usual.
If you left the recipient email blank, find the card on the **Cards** tab under **Gift cards** and give the buyer the value in the **Code** column.
Give a free gift card [#give-a-free-gift-card]
Use this to make up for a problem, run a giveaway or donate a card. Nobody is charged.
1. Go to **Gift cards** and open the **Cards** tab.
2. Click **Issue gift card**.
3. Pick an amount, or type any amount.
4. Optional: choose a design.
5. Enter a **Recipient name** and **Recipient email**. Leave the email blank to give out the code yourself.
6. Optional: add a message and change the expiry.
7. Click **Issue card**.
You don't need to publish gift cards to give free ones.
{/* 🖼️ Screenshot — _Gift cards → Cards tab, Issue gift card dialog._ Show the amount buttons, design picker, recipient fields and the Issue card button. · Alt: "Issue gift card dialog with amount, design, recipient and expiry fields" · Save as: public/help/point-of-sale/gift-card-issue.webp */}
What the recipient does [#what-the-recipient-does]
The email links to a page that shows the value and the code. The recipient clicks **Claim your gift** and signs in if asked. The value goes into their club credit at once.
They can also enter the code under **My Profile → Club Credit → Have a gift card?** and click **Redeem**.
Manage your gift cards [#manage-your-gift-cards]
The **Cards** tab lists every card with its code, amount, status, recipient and buyer. Filter by status or by source (*purchased*, *comped* for free cards, or *refund*).
| Action | Shows when | What it does |
| --------------------------- | -------------------------------------------- | -------------------------------------------------------------- |
| **Edit recipient** (pencil) | The card is active | Changes the recipient's name or email. |
| **Resend** | The card is active and has a recipient email | Sends the gift card email again. |
| **Void** | The card is active | Makes the card unusable. You can't undo this. |
| **Reverse** | The card is redeemed | Takes the club credit back and lets the card be claimed again. |
| **View history** (clock) | Always | Shows everything that happened to the card. |
{/* 🖼️ Screenshot — _Gift cards → Cards tab._ Show an active card (Edit, Resend, Void) and a redeemed card (Reverse), the filters and the Issue gift card button. · Alt: "Gift cards list with filters and row actions" · Save as: public/help/point-of-sale/gift-card-list.webp */}
Fix a card claimed by the wrong person [#fix-a-card-claimed-by-the-wrong-person]
1. On the **Cards** tab, find the card. Its status is *redeemed*.
2. Click **Reverse**, then **Reverse redemption**.
3. Send the code to the right person so they can claim it.
If the customer already spent some of the credit, you see **Allow a negative balance?** Click **Reverse and allow negative** to continue. Their club credit goes below zero.
Refund a gift card [#refund-a-gift-card]
Refund the order as you refund any other order. OpenCourt voids the card so nobody can claim it.
You can't refund a card after it is claimed. Reverse the redemption first.
See gift card sales [#see-gift-card-sales]
The **Report** tab shows cards sold, cards redeemed, and the value of cards not yet claimed. For how gift cards appear in your other sales reports, see [Financial reports and bookkeeping](/help/facility-operators/reports/financial-reports-and-bookkeeping).
If something goes wrong [#if-something-goes-wrong]
* **You can't see Gift cards in the menu** — Gift cards are off for your club, or you don't have the **Gift Cards** permission. → Contact OpenCourt support, or ask an admin to give you the permission.
* **Customers can't find gift cards, or the POS has no + Gift Card button** — **Publish to store & POS** is off. → Turn it on under **Gift cards → Settings**.
* **The recipient didn't get the email** — The address may be wrong, or the email is in spam. → Click **Edit recipient**, fix the email, then click **Resend**.
* **There is no Resend button** — The card has no recipient email. → Click **Edit recipient** and add one.
* **"This gift card has already been claimed."** — Someone already claimed it. → Click **View history** to see who. If it was the wrong person, reverse the redemption.
* **The refund is blocked because the card was redeemed** — The value is already the recipient's club credit. → Reverse the redemption, then refund the order.
Related [#related]
* [Club Credit](/help/facility-operators/customers-and-families/club-credit) — how customers spend the value of a gift card.
* [Creating and managing promo codes](/help/facility-operators/pricing-and-discounts/creating-and-managing-promo-codes) — promo codes never apply to gift cards.
* [POS & Products](/help/facility-operators/point-of-sale)
# Booking Upsells
When to Use Booking Upsells [#when-to-use-booking-upsells]
Use this feature to:
* **Rent equipment** (paddles, balls, towels, etc.) to new or visiting players.
* **Sell add-ons** such as drinks, snacks, or merchandise.
* **Include upgrades** for clinics, tournaments, or open plays (e.g., premium package, T-shirt, or extra session).
***
How to Set It Up [#how-to-set-it-up]
Step 1. Create or Select a Product [#step-1-create-or-select-a-product]
1. Go to **Products** in the left-hand menu.
2. Click **Create New Product** if it doesn’t exist yet.
3. Fill in the product name, description, and price.\
*(Example: “Paddle Rental – $5”)*
4. Save the product.\
More about adding a new product find [here](/help/facility-operators/point-of-sale/adding-products).
Step 2. Add It as a Booking Upsell [#step-2-add-it-as-a-booking-upsell]
1. Go to **Settings → Booking Upsells.**
2. Click **Add Booking Upsell.**
3. Choose a product from the dropdown list.
4. Select where it should appear:
* **Court Reservations**
* **Events** (like Open Play or Clinics)
5. Set the **price** (fixed per item or per hour).
6. (Optional) Add a **max quantity** if you want to limit how many can be purchased.
7. Click **Create Booking Upsell** and confirm.
***
What Players See [#what-players-see]
When players book a court or join an event:
1. They’ll see an **“Add Services”** section before checkout.
2. Available upsells (like *Paddle Rental*) will appear there.
3. They can select one or more items and continue to payment.
4. The upsell cost is automatically added to their total.
***
What Admins See [#what-admins-see]
* In the **Admin Panel**, reservations with upsells show a **“+” icon** next to the booking.
* Click it to view which items were added and how many.
* At check-in, staff can quickly confirm which upsell items to provide (e.g., *2 paddle rentals*).
***
✅ With Booking Upsells, you can streamline rentals, increase revenue, and offer a smoother experience for both players and staff — all without leaving the booking flow.
# Creating and Managing Promo Codes
***
Creating a Promo Code [#creating-a-promo-code]
1. Go to **Promo Codes** in the admin panel.
2. Click **Add New Promo**.
3. Enter the **Promo Code** (for example, `WINTER2026`).
4. Toggle **Enabled** to make the promo code active.
5. (Optional) Add an **Internal Description** (for admin use only).
6. Add a **User-Facing Description**—this is what players see at checkout.
***
Set Validity & Usage Limits [#set-validity--usage-limits]
* **Valid From / Expires At**\
Define the date range when the promo code can be used.
* **Maximum Total Uses**\
Limit how many times the code can be used in total (e.g., first 100 redemptions).
* **Max Uses Per User**\
Limit how many times a single user can redeem the code (e.g., once per user).
* **Bookings from / Bookings until**\
Limit which *booking dates* the code discounts, separately from when it can be redeemed. See [Limit a promo code to specific booking dates](/help/facility-operators/pricing-and-discounts/limit-a-promo-code-to-specific-booking-dates).
> Leave limits empty to allow unlimited usage.
***
Choose the Discount Type [#choose-the-discount-type]
Under **Discount Configuration**, pick a **Discount Format**:
* **Percentage** — a share off the total (for example, 20% off).
* **Fixed Amount** — a flat sum off the total (for example, $5 off).
* **Free Hours** — free court time instead of money off (for example, one free hour). **Orders** codes only; it is not offered for a **Memberships & subscriptions** code, because a recurring charge has no court time to give away.
Then enter the **Discount Value**: the percentage, the dollar amount, or the number of hours.
**Free Hours** discounts court time, so it always applies to reservations and can never be pointed at store products or packages. The scope choice below is set for you when you pick it.
***
Select Where the Promo Applies [#select-where-the-promo-applies]
First answer **What kind of code is this?**:
* **Orders** — discounts court time, events, store products, and booking-pass packages. This is the usual choice.
* **Memberships & subscriptions** — discounts a recurring membership charge instead.
For an **Orders** code, **What this code applies to** is a **required** choice with four independent opt-ins. A code with nothing ticked is refused when you save, with a message telling you to pick at least one. There is no implicit "applies to everything".
| Opt-in | What it covers |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Court reservations** | Standalone court bookings. The label follows your club's own word for a court or bay. |
| **Events & programs** | Everything on the schedule. Narrow it further — see below. |
| **Store products** | Goods sold through the club store. Gift cards are never discountable. You can optionally limit the code to particular categories or products. |
| **Booking-pass packages** | Bundles of court time sold up front. All-or-nothing — you cannot target individual packages. |
Ticking **Events & programs** opens a three-way choice:
* **All events** — every category, including any added to OpenCourt later.
* **By event category** — tick from *Open Play*, *Tournament*, *League*, *Clinic*, *Lesson*, and *Other*.
* **By event tag** — pick from your club's event tags.
These three are mutually exclusive, and switching between them clears the previous answer rather than leaving it set out of sight.
Saving a **100%**-off code with no **Maximum Total Uses** raises a confirmation first. A per-customer limit does not clear it — that caps each person, not your club's total exposure.
***
Save and Share [#save-and-share]
Click **Create Promo Code** to save.\
Once created, share the code with your players. When they apply it at checkout, the discount will be calculated automatically and reflected in the total.\
\
This is how your players can apply it:
***
Example [#example]
**Promo Code:** `WINTER2026`\
**Discount:** 20% off\
**Valid:** January 1 – February 28 2026\
**Usage:** 1 time per user, up to 20 total redemptions\
**Applies to:** Court reservations and Open Play
Players who apply this code at checkout will instantly receive 20% off.
***
Editing Promo Codes [#editing-promo-codes]
Promo codes can be **edited at any time**:
1. Open the **Promo Codes** page.
2. Click **View Promo Code** next to the promo you want to update.
3. Make changes to discount rules, validity dates, limits, or eligibility.
4. Save your updates — changes apply immediately.
You can also **disable** a promo code at any time by toggling it off.
***
Turning a Promo Code On or Off [#turning-a-promo-code-on-or-off]
The **Promo Codes** list has an **Active** column with a toggle on every row, so you can switch a code on or off without opening it. The change takes effect immediately.
Turning a code off is not the same as deleting it: the code keeps its settings and its usage history, and you can turn it back on at any time.
A code stops working when **either** you switch **Active** off **or** its **Expires At** date passes.
***
Viewing Promo Code Details & Usage Reports [#viewing-promo-code-details--usage-reports]
When you click **View Promo Code**, you can:
* See all promo settings (discount type, value, eligibility, and dates).
* Review a **detailed usage report**, including:
* Each time the promo code was applied
* The user who used it
* Date and time of use
* The reservation or event it was applied to (with a direct link)
* Discount amount applied
This gives full visibility into how each promo code is performing.
***
Promo codes give clubs a flexible way to run promotions, reward players, and boost participation—while keeping full control over limits and eligibility.
# Pricing & Discounts
What a customer pays, and every lever you have to change it: the price of court time and events, the extras you offer at checkout, the codes you hand out to fill quiet hours, and putting money back when something is called off.
Set your prices [#set-your-prices]
* [Pricing Models](/help/facility-operators/pricing-and-discounts/pricing-models) — how court time and events are priced.
* [Booking Upsells](/help/facility-operators/pricing-and-discounts/booking-upsells) — offer extras alongside a booking.
Run a promotion [#run-a-promotion]
* [Creating and Managing Promo Codes](/help/facility-operators/pricing-and-discounts/creating-and-managing-promo-codes) — discount codes, what they apply to, and how to limit their use.
* [Limit a promo code to specific booking dates](/help/facility-operators/pricing-and-discounts/limit-a-promo-code-to-specific-booking-dates) — tie a code to the date being booked rather than the date it is redeemed, for a one-day promotion or a quiet weekday.
Give money back [#give-money-back]
* [Processing refunds](/help/facility-operators/pricing-and-discounts/processing-refunds) — refund a booking or an event purchase.
Related [#related]
* [Court Bookings](/help/facility-operators/court-bookings) and [Events & Programs](/help/facility-operators/events-and-programs) — the things these prices apply to.
* [Creating a free court hours pass](/help/facility-operators/booking-and-guest-passes/creating-a-free-court-hours-pass) — prepaid court time, priced separately from a single booking.
# Limit a promo code to specific booking dates
A booking-date window ties a promo code to **the date being booked** rather than the date the customer buys. Use it to fill a quiet Tuesday, run a one-day promotion, or discount a holiday weekend while still letting people book weeks ahead. *(About 2 minutes. You need an existing or new promo code.)*
You set this in the admin panel under **Promo Codes**. It needs the promo codes permission, the same one that lets you create codes at all.
Booking dates vs. valid dates — they answer different questions [#booking-dates-vs-valid-dates--they-answer-different-questions]
The promo code form has two date ranges, and they are independent. Setting one does not set the other.
| Fields | What they control | Example |
| -------------------------------------- | --------------------------------------------------------------- | -------------------------------------------- |
| **Valid From** / **Expires At** | **When the customer can redeem the code.** The checkout window. | The code stops working after March 31. |
| **Bookings from** / **Bookings until** | **Which dates can be booked with it.** The court date. | The code only discounts bookings on March 8. |
A code can have both. "Sell it all February, but it only discounts play on March 8" is **Valid From** February 1, **Expires At** February 28, **Bookings from** and **Bookings until** both March 8.
Before you begin [#before-you-begin]
* The code must be an **Orders** code — the kind that discounts reservations, events, products, and packages. Codes set to **Memberships & subscriptions** have no booking date, so the section is hidden for them.
* Decide the dates in your club's local time. Both fields are read in the club's timezone, not the customer's and not yours.
Set the booking-date window [#set-the-booking-date-window]
1. Go to **Promo Codes** in the admin panel.
2. Open the code you want to change with **View Promo Code**, or click **Add New Promo** to create one.
3. Scroll to the **Usage Limits & Validity** section.
4. Find the **Booking dates** group at the bottom of that section.
5. Pick a date in **Bookings from** — the earliest date a customer may book with the code.
6. Pick a date in **Bookings until** — the latest date a customer may book with the code.
7. Save the code.
The three shapes you can set [#the-three-shapes-you-can-set]
* **A range** — fill both fields. The whole of the first day and the whole of the last day are included.
* **A single day** — pick the same date in both fields. This is the shape for a one-day promotion.
* **An open end** — fill one field and leave the other empty. **Bookings from** alone means "this date onward"; **Bookings until** alone means "up to and including this date".
Leaving both empty removes the restriction, and the code discounts any booking date again.
What customers see [#what-customers-see]
A customer whose booking falls outside the window is told so by name at checkout, in your club's dates:
> Promo code "SPRING" is only valid for bookings on Mar 8, 2026.
The wording follows the shape you set — *on* one day, *between* two dates, *from* a date, or *until* a date. The discount is refused rather than quietly reduced, so nobody pays a surprise amount.
Where the window appears afterwards [#where-the-window-appears-afterwards]
* On the **Promo Codes** list, the code's row shows its booking window next to the word **Bookings**.
* On the code's detail page, a **Booking dates** row shows the same window.
* A code with no window shows neither, rather than displaying "any date".
Good to know [#good-to-know]
**An event is judged as a whole.** For a league, clinic, or any program with several sessions, **every** session must fall inside the window. A four-week league that starts inside your window but ends after it is refused, even if the customer is looking at a session that is inside. This is deliberate: the customer pays once for the whole program, not per session, so a partial match would discount dates you fenced off.
**A cart with several bookings must pass entirely.** If someone books three courts in one order and one of them is outside the window, the whole order is refused rather than discounting the other two.
**Cancelled sessions are ignored.** A session you have cancelled does not count against the window.
**A booking-date code cannot be used on retail alone.** If the cart holds only store products or booking-pass packages, there is no booking date to check, so the code is refused with "only applies to bookings." Use a separate code for retail promotions.
If something goes wrong [#if-something-goes-wrong]
* **A customer says the code is refused, and the date looks right to you** — check the timezone. The window covers whole days in the club's timezone, so a late-evening slot that is already the next day in UTC is still inside the club's day.
* **Someone joining a multi-week program is refused, though the session they picked is inside the window** — every session of that program has to be inside. Widen **Bookings until** to cover the last session, or use a code without a booking window for that program.
* **The code works on courts but is refused at checkout for a product** — the cart has no booking in it. A code carrying a booking window only applies to reservations and events.
* **You cannot find the Booking dates group** — the code is set to **Memberships & subscriptions** under **What kind of code is this?**. Switch it to **Orders**, and note that switching clears any booking dates already set.
* **The code discounts bookings you meant to exclude** — check that you set **Bookings from** / **Bookings until** and not **Valid From** / **Expires At**. The second pair limits when the code can be typed in, not what it discounts.
Related [#related]
* [Creating and Managing Promo Codes](/help/facility-operators/pricing-and-discounts/creating-and-managing-promo-codes)
# Pricing Models
1. Price Per Court Per Hour [#1-price-per-court-per-hour]
This model fits clubs that want to charge for **court time only**, regardless of how many players show up.\
\
*Example:* Whether it’s 2 players, 4 players, or a bigger group that’s happy to rotate on one court, the cost is **$30 per hour for the court**.
2. Price Per Person Per Hour [#2-price-per-person-per-hour]
This model fits clubs that want to track **individual usage** and charge each participant separately.\
\
*Example:* If the rate is **$8 per person per hour**, 4 players sharing a 1-hour reservation pay **$32 total**.
3. Price Per Person Per Day [#3-price-per-person-per-day]
This model fits clubs that want to offer a **day-pass style** option covering all eligible play within the club’s daily limits. This model is pretty flexible, so day fee can cover:
* Court reservations (either if they book a court themselves or join someone else’s reservation)
* Open Plays
* Any other events (clinics, tournaments, etc)
It’s up to the club what they want to include in a day pass.\
\
*Example 1*: Day Fee is $40, and it allows to book courts up to 3 hours per day (can be multiple reservations), and they can participate in Open Play.\
*Example 2.* Day Fee is $30, and it covers reservations - either their own or they can join someone else’s reservation / Open Game. But they have to pay separately for Open Plays or any other events.
4. Fixed Price Per Reservation [#4-fixed-price-per-reservation]
This model fits clubs that want to charge a **flat fee** per booking regardless of duration (within the maximum allowed reservation length).\
\
Example: A guest pays $20 and can book a court up to 2 hours — doesn’t matter if it’s 1 hour or 2, it’s the same price.
5. New: Flexible Member/Non-Member Pricing [#5-new-flexible-membernon-member-pricing]
You can now create more dynamic pricing structures. Mix them and create rules depending on who made a reservation - a member or non-member.\
\
*Example:* Non-members pay a court-per-hour rate that covers the entire court, no matter how many people they bring. Guests are included at no extra cost.\
However, if a member creates a reservation or an Open Game and a non-member joins it, the non-member pays a different fee (e.g., per-person per-hour or a flat guest fee).
# Processing refunds
How Automatic Refunds Work [#how-automatic-refunds-work]
* When a player books a reservation, they’ll see your **cancellation policy** (for example: *24 hours in advance*).
* If they cancel **at least x hours before the start time (depends on your cancellation policy)**, the system will:
* Automatically refund the payment.
* Send them a confirmation email.
* Mark the transaction as **Refunded** in your admin dashboard (with a red “Refunded” status line).
***
How Manual Refunds Work [#how-manual-refunds-work]
If a player cancels **less than x hours before the start time (depends on your cancellation policy)**, the system will not issue a refund automatically. However, admins can still process one manually if desired:
1. Go to the **Transactions** tab.
2. Find the reservation in the list.
3. Click the three dots under **Actions**.
4. Select **Refund**.
The refund will then be issued and recorded in the Transactions log.
***
Things to Keep in Mind [#things-to-keep-in-mind]
* The automatic refund window depends on the **cancellation policy** you’ve set (e.g., 24 hours, 48 hours, etc.).
* If your club’s policy is **no refunds within 24 hours**, only the automatic system applies—players won’t get a refund unless you issue one manually.
* All refunded transactions are clearly marked in red for easy tracking.
***
✅ With this setup, players have clarity on refunds, and admins stay in full control when exceptions need to be made.
# Financial Reports and Bookkeeping
These Reports Are Operational, Not a General Ledger [#these-reports-are-operational-not-a-general-ledger]
OpenCourt's Revenue and Itemized reports are designed for day-to-day facility management — understanding what sold, reconciling payments, and identifying trends. They are not a substitute for formal accounting software.
For tax filing and official bookkeeping, we recommend cross-referencing with:
* Your **Stripe dashboard** for card payment records and payout details
* Your **bank statements** for cash deposit reconciliation
* Your **accounting software** (QuickBooks, Xero, etc.) for the official books
The **CSV export** on both reports makes it easy to pull data into your accounting tools.
***
Understanding Club Credits and Gift Cards [#understanding-club-credits-and-gift-cards]
How Club Credits Work in Reports [#how-club-credits-work-in-reports]
Club credits are store credit balances that customers can use to pay for orders. When a customer pays with club credits, the transaction appears in your sales figures but does not appear in **Net Collected**, because no new money entered the system.
This is why the report separates the sales story from the payments story:
* **Net Sales** reflects the total value of goods and services sold, regardless of payment method.
* **Net Collected** reflects the actual card and cash payments received.
Gift Cards and Double-Counting in Gross Sales [#gift-cards-and-double-counting-in-gross-sales]
When a customer purchases a gift card, it appears as a sale in Gross Sales at the time of purchase. When the gift card is later redeemed and the resulting club credits are spent on another purchase, that second transaction also appears in Gross Sales.
This means the underlying dollar value can appear in Gross Sales twice — once for the gift card and once for the item purchased with credits. This is standard for operational reporting and is consistent with how platforms like Square and Mindbody handle gift card reporting.
**Net Collected remains accurate.** The gift card purchase adds to Net Collected (real money came in), but the subsequent credit-funded purchase does not (no new money came in). If you need to reconcile actual cash flow, Net Collected is the figure to use.
**For formal accounting:** Under standard accounting practices (GAAP), gift card revenue is typically treated as deferred revenue (a liability) at the time of sale, and recognized as income when the gift card is redeemed. Consult your accountant for how to handle this in your formal records.
***
Platform Fees [#platform-fees]
Platform Fees (OpenCourt service fees) are only charged on certain pricing plans (eg Core+). OpenCourt platform fees are pass-through costs added to the customer's price. They are not deducted from your revenue.
For example:
* You set a lesson price of **$50**
* The platform fee is **$1**
* The customer pays **$51**
* You receive **$50**, OpenCourt receives **$1**
In the reports, **Net Sales** already excludes platform fees and represents what your business earned. The fees are shown separately in the OpenCourt Fees section for transparency.
***
Refunds [#refunds]
Refunds appear as separate line items in the reports and reduce both **Net Sales** and **Net Collected**. OpenCourt supports partial refunds — only the refunded portion is subtracted from the totals.
In the financial summary:
* **Refunds** shows the total sales value returned
* **Tax Refunded** shows the tax portion returned
* **Card Refunds** and **Cash Refunds** show the actual money returned by payment method
* **Club Credits Refunds** shows credits restored to customer balances
***
Reconciling with Stripe [#reconciling-with-stripe]
Every card transaction in the reports includes a **Stripe link** that takes you directly to the payment in your Stripe dashboard. This is useful for:
* Verifying individual transactions
* Checking the status of refunds
* Matching report totals against Stripe's payout reports
**Tip:** Stripe's payout timing may differ from your report dates. OpenCourt reports show transactions by the date the order was placed, while Stripe payouts may arrive 2–7 business days later depending on your payout schedule.
# Reports
The revenue and itemized reports, and how to reconcile them with your bookkeeping.
Articles [#articles]
* [Understanding the Revenue Report](/help/facility-operators/reports/understanding-the-revenue-report) — The Revenue Report gives you a high-level view of your sales activity.
* [Understanding the Itemized Report](/help/facility-operators/reports/understanding-the-itemized-report) — The Itemized Report gives you a detailed, line-item-level view of every transaction.
* [Financial Reports and Bookkeeping](/help/facility-operators/reports/financial-reports-and-bookkeeping) — This article covers important context for facility owners and bookkeepers who use OpenCourt's financial reports for accounting and reconciliation purposes.
# Understanding the Itemized Report
The Itemized Report gives you a detailed, line-item-level view of every transaction. You'll find it in the admin panel under **Reports > Itemized**.
Unlike the Revenue Report (which shows one row per order), the Itemized Report shows **one row per line item**. If a customer bought three different items in a single order, that order appears as three separate rows — one for each item with its own price, discount, tax, and fee breakdown.
***
When to Use the Itemized Report [#when-to-use-the-itemized-report]
The Itemized Report is best for:
* **Auditing specific charges** — verifying that the correct price, discount, or tax was applied to an individual item
* **Filtering by product type** — viewing only court bookings, memberships, coaching lessons, or a specific product category
* **Reconciling line-item details** — checking per-unit pricing and quantities for product sales
For a higher-level overview of daily sales and payment methods, use the Revenue Report instead.
***
Financial Summary [#financial-summary]
The Itemized Report shares the same financial summary section as the Revenue Report, displayed at the top of the page. This includes the Sales Breakdown, Tax Summary, OpenCourt Fees, and Payment Method Breakdown for the selected date range.
For a detailed explanation of each metric, see the Understanding the Revenue Report article.
***
Table Columns [#table-columns]
Each row represents a single line item within an order:
| | ColumnWhat it means |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Order ID** | The unique order identifier. Multiple rows can share the same Order ID when an order contains multiple items. |
| **Transaction Time** | When the order was placed. |
| **Customer / Email** | The customer who made the purchase. |
| **Line Item** | Description of the item — product name, court booking, coaching lesson, membership, etc. |
| **Category** | The product category, if applicable. |
| **Price** | The per-unit price before any discounts. |
| **Qty** | Quantity purchased. For products (merchandise, food, etc.), this is the actual quantity ordered. For court bookings, lessons, memberships, event fees, and other non-product items, this is always 1. |
| **Extended Price** | Price multiplied by Qty — the full amount before discounts. |
| **Discount / Adjustment** | The discount applied to this line item from promo codes or manual adjustments. Shown as a negative number when a discount was applied. |
| **Taxable Base** | The amount subject to tax: Extended Price plus the Discount (which is negative when a discount exists). |
| **Sales Tax** | Tax charged on this line item. |
| **OpenCourt Service Fee** | Platform fee on this line item. |
| **Total Charged** | The final amount charged to the customer for this line item: Taxable Base + Sales Tax + Service Fee. |
| **Stripe** | Link to view the payment in your Stripe dashboard. |
***
Filtering [#filtering]
The Itemized Report supports filtering by **product type and category**, in addition to the date range filter. Use the filter to narrow down to specific types of transactions:
* POS products
* Court bookings
* Player fees
* Daily fees
* Memberships
* Equipment rentals
* Coaching lessons
* Custom items
* Specific product categories
This is useful when you need to review transactions for a particular part of your business — for example, viewing only coaching lesson charges for the month, or filtering to a specific product category to check pricing.
***
How Refunds Appear in the Table [#how-refunds-appear-in-the-table]
When a full refund is issued, each refunded line item gets its own **refund row** directly below the original item, with "(Refunded)" appended to the description and negative amounts.
**Important note about partial refunds:** Partial refunds may not always appear as individual line item rows in the Itemized Report. This is because a partial refund is sometimes issued as a flat dollar amount rather than being tied to specific items, and the system cannot always determine which line items the refund applies to. When this happens, the refund is still reflected in the **financial summary** at the top of the page (which calculates from payment-level data), but it may not appear as a line item row in the table below.
If you need the most complete picture of refund activity, use the **Revenue Report** — it shows all refunds as separate order-level rows regardless of how the refund was attributed.
***
Exporting Data [#exporting-data]
Click the **Export** button to download the currently filtered data as a CSV file. The export includes all visible columns and respects your current filters, so you can export just the subset of transactions you need.
# Understanding the Revenue Report
The Revenue Report gives you a high-level view of your sales activity. You'll find it in the admin panel under **Reports > Revenue**.
Each row in the table represents a single **order**, with columns showing how the customer paid (card, cash, or club credits), what discounts were applied, and the tax and fees collected. A financial summary section at the top aggregates everything for the selected date range.
***
Financial Summary [#financial-summary]
The summary at the top of the report is organized into four sections, each answering a different question.
Sales Breakdown — "How much did we sell?" [#sales-breakdown--how-much-did-we-sell]
| | MetricWhat it means |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Gross Sales** | Total value of all items sold at their listed price, before any discounts or adjustments. |
| **Discounts** | Total value of promo codes, manual POS adjustments, and other price reductions. Only appears when discounts were applied. |
| **Subtotal** | Gross Sales minus Discounts — what customers were actually charged before tax and fees. |
| **Refunds** | Total value returned to customers for cancelled or refunded orders. Includes both card refunds and club credit refunds. Only appears when refunds occurred. |
| **Net Sales** | Your final sales figure: Subtotal minus Refunds. Excludes tax and platform fees — this represents the value of goods and services sold. |
**Formula:** Gross Sales − Discounts = Subtotal − Refunds = **Net Sales**
Tax Summary [#tax-summary]
| | MetricWhat it means |
| ----------------- | ------------------------------------------------------------------------------------ |
| **Tax Collected** | Total sales tax charged on orders. |
| **Tax Refunded** | Sales tax returned to customers as part of refunds. |
| **Net Tax** | Tax Collected minus Tax Refunded — the tax amount you are responsible for remitting. |
This section only appears when tax was collected during the selected period.
OpenCourt Fees [#opencourt-fees]
| | MetricWhat it means |
| ------------------ | ------------------------------------------------ |
| **OpenCourt Fees** | Total platform fees charged on orders. |
| **Fees Refunded** | Platform fees returned when orders are refunded. |
| **Net Fees** | OpenCourt Fees minus Fees Refunded. |
This is only relevant on our Core+ plan or other plans where OpenCourt collects a service fee.
For most of our customers, platform fees are added to the customer's price — they are not deducted from your revenue. If you price a lesson at $50 and the platform fee is $1, the customer pays $51 and you receive $50.
Payment Method Breakdown — "How did money flow in and out?" [#payment-method-breakdown--how-did-money-flow-in-and-out]
| | MetricWhat it means |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Card Payments** | Total payments received via credit and debit cards. |
| **Card Refunds** | Total refunds issued back to cards. |
| **Cash Payments** | Total payments received in cash. |
| **Cash Refunds** | Total cash refunds issued. |
| **Club Credits Applied** | Total club credits customers used to pay for orders. Club credits are store credit balances and do not represent new incoming revenue. |
| **Club Credits Refunds** | Club credits returned to customer balances when orders are refunded. |
| **Net Collected** | Card and cash payments received, minus card and cash refunds. **This is the actual money your business collected.** Club credits are excluded because they are internal balances, not incoming payments. |
***
How Net Sales and Net Collected Relate [#how-net-sales-and-net-collected-relate]
The summary is designed to tell two separate stories:
1. **The sales story** (top row): How much you sold, after discounts and refunds — ending at **Net Sales**.
2. **The payments story** (bottom section): How customers paid and how much actual money came in — ending at **Net Collected**.
These two numbers will usually differ, and that's expected:
* **Tax and fees** are collected from customers but are not part of your sales value, so they increase Net Collected relative to Net Sales.
* **Club credits** are internal balances, not new money, so they decrease Net Collected relative to what you'd expect from the sales total.
**Formula:** Net Sales + Net Tax + Net Fees − Net Club Credits Used = **Net Collected**
Worked Example [#worked-example]
| | MetricAmount |
| -------------------- | ------------ |
| Gross Sales | $1,000.00 |
| Discounts | −$50.00 |
| **Subtotal** | **$950.00** |
| Refunds | −$100.00 |
| **Net Sales** | **$850.00** |
| | |
| Net Tax | $68.00 |
| | |
| Card Payments | $918.00 |
| Club Credits Applied | $108.00 |
| Card Refunds | −$108.00 |
| **Net Collected** | **$810.00** |
Reconciliation: $850 (Net Sales) + $68 (Net Tax) − $108 (Club Credits) = **$810** (Net Collected) ✓
***
Table Columns [#table-columns]
Each row represents a single order:
| | ColumnWhat it means |
| ------------------------- | -------------------------------------------------- |
| **Order ID** | The unique order identifier. |
| **Transaction Time** | When the order was placed. |
| **Customer / Email** | The customer who made the purchase. |
| **Order Item(s)** | A summary of all items in the order. |
| **Total Amount** | The total charged for the entire order. |
| **Cash Amount** | Portion paid in cash. |
| **Card Amount** | Portion paid by card. |
| **Club Credit** | Portion paid with club credits. |
| **Discount / Adjustment** | Total discounts applied across all items. |
| **Taxable Base** | Total amount subject to tax. |
| **Sales Tax** | Total tax charged. |
| **OpenCourt Service Fee** | Total platform fees. |
| **Stripe** | Link to view the payment in your Stripe dashboard. |
***
How Refunds Appear in the Table [#how-refunds-appear-in-the-table]
Refunds are shown as **separate rows** in the table, distinct from the original order. When an order is fully or partially refunded, you'll see:
1. The **original order row** with the full positive amounts
2. A **refund row** below it with negative amounts, showing what was returned
For partial refunds, the refund row only reflects the refunded portion — not the full order amount. Both card refunds and club credit refunds appear this way.
Each refund row includes its own Stripe link so you can verify the refund transaction directly in Stripe.
***
Exporting Data [#exporting-data]
Click the **Export** button to download the currently filtered data as a CSV file. The export includes all visible columns and can be imported into Excel, Google Sheets, or your accounting software for further analysis.
# DUPR Rating
***
Where to find it [#where-to-find-it]
Go to **My Profile → Skills → Pickleball tab**. Scroll down to the **DUPR Rating** section.
***
Connecting your DUPR account [#connecting-your-dupr-account]
1. Tap **Connect DUPR Account**.
2. A DUPR sign-in window opens — log in with your DUPR credentials and grant access.
3. Once you approve, the window closes automatically and your ratings appear.
Your **singles** and **doubles** ratings are pulled directly from DUPR and displayed on your profile.
> **Don't have a DUPR account?** Create one at [mydupr.com](http://mydupr.com) before connecting.
***
What the badges mean [#what-the-badges-mean]
Once connected, you may see one or two badges next to your rating:
| | **BadgeMeaning** |
| ------------ | ----------------------------------------------- |
| **DUPR+** | You have an active DUPR+ (Premium) subscription |
| **Verified** | Your DUPR rating has been verified by DUPR |
No badge is shown for a standard DUPR account — your ratings still display normally.
***
Keeping your rating up to date [#keeping-your-rating-up-to-date]
OpenCourt refreshes your DUPR rating automatically every day. If you just played a tournament or match and want the latest number right away, tap the **refresh icon** (↻) next to your rating.
***
"DUPR account restricted" message [#dupr-account-restricted-message]
This means your DUPR account doesn't have an active subscription, which DUPR requires for third-party integrations. Log in to [mydupr.com](http://mydupr.com) and check your subscription status. Once your DUPR subscription is active, reconnect your account.
***
Connection expired [#connection-expired]
If you see **"Your DUPR connection has expired"**, tap **Reconnect DUPR Account** and sign in again. This happens when your DUPR credentials expire after 90 days.
***
Disconnecting [#disconnecting]
Tap the **unlink icon** (⛓️💥) next to your rating to remove the connection. Your self-rated and club-verified ratings are not affected.
***
DUPR-gated events [#dupr-gated-events]
Club admins can restrict events to players whose DUPR rating falls within a specific range — for example, "DUPR singles 4.0–4.5 only." If your connected DUPR rating doesn't fall in that range, you won't be able to register. Make sure your account is connected and your rating is current before signing up for rated events.
Learn more about skill-gated events [here](/help/facility-operators/skill-ratings/skill-rating-create-balanced-and-competitive-games).
# Skill Rating
Skill ratings let you run balanced, competitive events. Assign ratings yourself or connect DUPR and WPR.
Articles [#articles]
* [Skill Rating: Create Balanced and Competitive Games](/help/facility-operators/skill-ratings/skill-rating-create-balanced-and-competitive-games) — The Skill Rating feature helps clubs organize events where players are evenly matched — ensuring every game feels competitive, fair, and fun.
* [Setting skill ratings to players](/help/facility-operators/skill-ratings/setting-skill-ratings-to-players)
* [WPR (WorldPadelRating)](/help/facility-operators/skill-ratings/wpr-worldpadelrating) — WorldPadelRating (WPR) is the global rating system for padel.
* [DUPR Rating](/help/facility-operators/skill-ratings/dupr-rating) — DUPR (Dynamic Universal Pickleball Rating) is the global standard rating system for pickleball.
# Setting skill ratings to players
OpenCourt supports two kinds of skill ratings for players:
* [**Self-declared ratings**](/help/facility-operators/skill-ratings/setting-skill-ratings-to-players#ektdrdr3zml) – set by players themselves in their own account.
* [**Club-verified ratings**](/help/facility-operators/skill-ratings/setting-skill-ratings-to-players#e65yircc6l5) – set by admins/coaches to validate player skills for gated events.
Here’s how each one works and how to set them up.
How players set their self-declared skill ratings [#how-players-set-their-self-declared-skill-ratings]
Players can add or update their own skill rating through their OpenCourt account. This is typically used for casual play or when the club allows self-declared ratings for open events.
1. Open your **OpenCourt account** (on desktop or on the OpenCourt app), and click on the **My Profile** tab. You can also use this link: [**app.getopencourt.com/my-profile**](https://app.getopencourt.com/my-profile) .
2. Click on **Skill Ratings.**
3. Under each sport (**Pickleball**, **Tennis**, or **Padel**), select your current skill level by using the slider.
4. Click **Update** to save your rating.
> 🔔 Note: This rating is self-declared — it can be changed by the player anytime. Clubs can view it but can’t modify it.
***
How club admins set club-verified ratings for players [#how-club-admins-set-club-verified-ratings-for-players]
For events that require more accurate ratings (like advanced open play or gated tournaments), clubs can assign **club-verified ratings** directly to player accounts.
> Ensure **Skill Rating** is enabled for your club. Contact the OpenCourt team to activate this feature for your club.
1. In the **Admin Panel**, go to the **Users** tab.
2. Use the search bar to find and click on the player’s name.
3. Navigate to the **Skill Rating** section in their profile. You’ll see:
* **Self-rated** (shows if the user has set a personal rating).
* **Club-verified** (displays any existing verified rating).
4. To assign a club-verified rating:
* Click **Set Club Verified Rating**.
* Choose a value from the slider.
5. Click **Update Rating** to save.
Once saved, the player will see this verified rating when they log into their account.
> ✅ Verified ratings are required to join events that have **enforced skill requirements**. They can’t be changed by the player.
What's next [#whats-next]
* To create an event with required rating, check out [this guide](https://opencourt.gitbook.io/opencourt-help-center/opencourt-essentials/events-and-programs/how-to-use-event-gating-by-rating).
# Skill Rating: Create Balanced and Competitive Games
Why Use Skill Ratings [#why-use-skill-ratings]
* ✅ **Better Matchups:** Players compete with others at a similar level.
* 🏆 **More Enjoyable Play:** Balanced games keep everyone engaged.
* 💬 **Clear Expectations:** Players know if an event is right for them.
* 🔁 **Higher Retention:** When players have good match experiences, they return more often.
***
How to Set Up a Skill-Based Event [#how-to-set-up-a-skill-based-event]
1. Go to **Events & Programs** and click **Create New Event.**
2. Fill out event details (name, description, time, participant limit, etc.).
3. Below the **Pricing** block, find the **Skill Rating** section.
4. Toggle **Skill Rating** ON.
5. Choose whether the skill rating will be:
* **Recommended** – players see the ideal level for the event (e.g., *3.0–3.5*).
In this case, players will see only a recommendation to sign up if they meet this skill level
* **Enforced** – only players with the required skill level can join.
In this case, players won’t even see the Join button unless they meet the requirements. They’ll be prompted to set their skill level in their account if they haven’t done it yet:
Or if their skill level doesn’t meet the requirements, they’ll see this message:
***
Enforced Skill Rating Options [#enforced-skill-rating-options]
When you enforce a skill rating, you can choose how the system verifies it:
* [**Self-Declared Rating:**](/help/facility-operators/skill-ratings/setting-skill-ratings-to-players#ektdrdr3zml) The system uses the player’s own skill level from their profile.
* [**Club-Verified Rating**](/help/facility-operators/skill-ratings/setting-skill-ratings-to-players#e65yircc6l5)**:** Only players whose rating has been reviewed and confirmed by the club (coach or admin) can join.
***
What Players See [#what-players-see]
* When players open an event, they’ll see the **required skill level** (e.g., *3.5–4.0*).
* If their rating is **below** or above the required level, they won’t be able to join.
* If they **don’t have a rating yet**, they’ll see a button prompting them to **Set Your Skill Rating**.
* After setting or updating their rating in **My Profile**, they can join any event within their range.
***
✅ Using Skill Rating makes your events more organized, competitive, and rewarding for everyone — from beginners finding their groove to advanced players chasing great matches.
# WPR (WorldPadelRating)
> **Note:** WPR connection is only available at clubs that have enabled the WPR integration. If you don't see this section, your club hasn't turned it on yet.
***
Where users can find it [#where-users-can-find-it]
Go to **Profile → Skills → Padel tab**. Scroll down to the **WorldPadelRating** section.
***
How users connect their WPR account [#how-users-connect-their-wpr-account]
1. Tap **Connect WPR Account**.
2. A WorldPadelRating sign-in window opens — log in with your WPR credentials and authorize OpenCourt.
3. Once you approve, the window closes and your ratings appear.
> **Don't have a WPR account?** Sign up at [worldpadelrating.com](http://worldpadelrating.com) first.
***
Your two WPR ratings [#your-two-wpr-ratings]
WPR tracks two separate ratings:
| | **RatingWhat it measures** |
| --------------------- | ------------------------------------------------------------- |
| **WPR** (Competition) | Your performance in official, competitive WPR-tracked matches |
| **WPR-s** (Social) | Your rating from social and recreational play |
Both are shown on your profile when available. It's normal to have one but not the other, or for one rating to say "No ratings available yet" if you haven't played enough tracked matches in that category.
***
Subscription badges [#subscription-badges]
Depending on your WPR account, you may see one or more badges:
| | **BadgeMeaning** |
| -------------------- | ----------------------------------------------------- |
| **RedPadel Premium** | You have an active RedPadel Premium subscription |
| **USPA** | You have a United States Padel Association membership |
| **USPA Premium** | You have a USPA Premium membership |
No badge is required to display your ratings — these simply reflect your WPR account tier.
***
Keeping your rating up to date [#keeping-your-rating-up-to-date]
OpenCourt refreshes your WPR rating automatically every day. To pull the very latest numbers immediately after a match, tap the **refresh icon** (↻) next to your rating.
***
Connection expired [#connection-expired]
WPR connections expire after approximately 7 days and are refreshed automatically by OpenCourt in the background. If auto-refresh fails (for example, if you changed your WPR password), you'll see **"Your WPR connection has expired"** — tap **Reconnect WPR Account** and sign in again.
***
Disconnecting [#disconnecting]
Tap the **unlink icon** (⛓️💥) to remove your WPR connection. Your self-rated and club-verified padel ratings are not affected.
***
WPR-gated events [#wpr-gated-events]
Club admins can restrict padel events to players whose WPR rating falls within a specific range — using either your competition rating (WPR) or social rating (WPR-s). For example, an event might require "WPR competition 5.0–7.0." If a player’s connected rating doesn't qualify, they won't be able to register.
Learn more about skill-gated events [here](/help/facility-operators/skill-ratings/skill-rating-create-balanced-and-competitive-games).
# Checking if a customer signed a waiver
You may occasionally need to confirm whether a customer has signed your club’s waiver. You can easily check it on their user’s profile page.
***
Steps to Check Waiver Status [#steps-to-check-waiver-status]
Method 1. Open their user’s profile on Users page [#method-1-open-their-users-profile-on-users-page]
1. Click Users page in the left-hand menu.
2. Use the search bar to find the customer by name or email
3. Click the customer’s name to view their full profile
4. Under **Details**, scroll to “**Membership & Waiver**” section
5. Look for the **Waiver Status** under this section
* **If Waiver is signed** If the customer has already completed the waiver, you’ll see:
* **If Waiver is not signed** If the waiver has not been signed, you'll see:
***
Method 2: Using the QR Code Scanner or Find Customer [#method-2-using-the-qr-code-scanner-or-find-customer]
Whip this out for quick checks at the front desk, especially during busy periods or for first-time visitors. It’s ideal when a player’s standing right there with their QR code ready.
1. **In the admin panel, click "Scan Customer QR"**
2. **Ask the customer to show their QR code** The user must have the OpenCourt app (or your branded app) ready, or they can visit [**app.getopencourt.com**](http://app.getopencourt.com/) and go to the "**My Profile"** tab where they can find their own **Check-In QR code**.
3. **Scan the Customer's QR Code and View the player’s info**
* Once scanned, a **Customer Details** pop-up appears.
* In the **Customer Details** pop-up, look under **Waiver Status** to see if it’s signed or not signed.
***
💡 Additional tips [#-additional-tips]
* If a **new version** of your waiver is created by the OpenCourt team, all users will need to **sign it again**, regardless of whether they signed a previous version.
* If needed, you can **send the club waiver link** to the customer directly: `https://app.getopencourt.com/club//waiver`
* The system will also **prompt users automatically** during court bookings, event registration, and membership purchases if a waiver signature is missing.
# Waivers
How customers sign your waiver online or at the front desk, and how to check who has signed.
Articles [#articles]
* [Signing a waiver at the Front Desk](/help/facility-operators/waivers/signing-a-waiver-at-the-front-desk) — You can create a QR code for your waiver and keep it printed at the front desk.
* [Signing a waiver online](/help/facility-operators/waivers/signing-a-waiver-online) — If your club requires players to sign a waiver before participating, OpenCourt automatically prompts users to complete it during key actions.
* [Checking if a customer signed a waiver](/help/facility-operators/waivers/checking-if-a-customer-signed-a-waiver) — You may occasionally need to confirm whether a customer has signed your club’s waiver.
# Signing a waiver at the Front Desk
You can create a QR code for your waiver and keep it printed at the front desk. When a new customer needs to sign the waiver, they can scan this QR code, and quickly sign it at the spot.
Use [**this QR code generator**](https://v0-open-court.vercel.app/) or any other to generate a QR code of your waiver - just put a link of your waiver in the URL field `https://app.getopencourt.com/club//waiver`
When they open this link they'll be prompted to fill out their name and email and sign the waiver.
What's next [#whats-next]
Once they sign the waiver, they're automatically added to the platform. You can find them on Users tab and add them as participants to any events (Open Play, Tournament, Clinic etc), or book a court for them, or sell them a membership.
# Signing a waiver online
If your club requires players to sign a waiver before participating, OpenCourt automatically prompts users to complete it during key actions. Once a waiver is signed, it’s stored in the customer’s profile and accessible to club admins.
***
When are customers prompted to sign the waiver? [#when-are-customers-prompted-to-sign-the-waiver]
Customers will be asked to sign the waiver **automatically** if they haven’t already signed the latest version for your club. This happens during:
* **Booking a court**
* **Joining an event**
* **Purchasing a membership**
***
How customers can sign the waiver [#how-customers-can-sign-the-waiver]
There are **four main ways** users can complete the waiver:
**1. During court bookings**
If a player tries to book a court and hasn't signed the current waiver:
* A pop-up will appear with the waiver text and custom input fields.
* The booking cannot be completed until the waiver is signed.
**2. When joining an event**
If an event has open registration but the user hasn't completed the latest waiver version:
* They’ll be asked to sign the waiver before confirming attendance.
**3. When purchasing a membership**
During the checkout process for a membership:
* The system checks if a valid waiver is on file.
* If not, the user must sign the latest waiver before payment is processed.
**4. Through the club’s waiver link**
If you want to collect waiver signatures manually or ahead of time:
* Send users this link: `https://app.getopencourt.com/club//waiver`
* They can sign it directly from that page — no bookings or purchases required.
***
💡 Tips for Club Admins [#-tips-for-club-admins]
* **You cannot add or edit waivers yourself** — only the OpenCourt team can do this at the moment. This will change soon!
* Each time a new waiver version is added to your club, **all users will be prompted to sign it again**, even if they signed an older version.
# Embedding OpenCourt into your website
There are several ways you can link to or embed OpenCourt on your website to give your visitors direct access to your club’s schedule and events.
In all examples below, replace your\_club\_id with your club’s unique ID. If you don’t know your club ID, please contact your OpenCourt support representative.
🔗 Direct Links [#-direct-links]
These URLs take users straight to your club’s pages on OpenCourt:
Club Home Page [#club-home-page]
```
https://app.getopencourt.com/club/your_club_id
```
This URL will open your club's home page, such as this:
Club Schedule [#club-schedule]
```
https://app.getopencourt.com/club/your_club_id/schedule
```
Most often you'll link a "Book a Court" button on your website to take users to this page.
***
📥 Schedule & Programs Embedding via iFrame [#-schedule--programs-embedding-via-iframe]
You can embed your OpenCourt schedule directly on your website using an `