<!-- https://unlockos.io/manual/membership-plans -->

# Membership Plans and Usage Quotas

## Overview

Membership plans let you define who can access your facility as a member, how they are billed, whether they need approval before starting, and how many visits, hours, or bookings they are allowed per period. When a quota is exceeded, you can either block further usage or automatically charge an overage fee via Stripe Invoice Item.

Members can view their current quota status at a glance on the home screen of the Member App through the QuotaBar component.

---

## Detailed Features

## Feature 1: Application Flow

When creating a plan, choose how applicants progress to an active subscription:

| Flow | How it works |
|------|-------------|
| **Pay first** (default) | The applicant pays during signup. If `auto_approve` is off, the subscription becomes active only after staff manually activate it in the Membership tab. |
| **Apply first** | The applicant submits an application form with no payment. Staff review the application in the **Pending Approvals** tab and approve or reject it. Approved applicants receive an email and are prompted to complete payment to activate their membership. |

### Apply-First Plan Settings

When **Apply first** is selected:
- Applications can be submitted with no payment (payment happens after approval)
- Submitted answers are displayed on each pending application card so staff can review them before approving

> To collect additional information at signup (name, contact info, etc.), you can configure this on **either** application flow, not just Apply first. It's set up in the **Application Form** section that appears after you save the plan (see [Feature 1.5: Setting Up the Application Form](#feature-15-setting-up-the-application-form)).

### Approving and Rejecting Applications (Pending Approvals Tab)

1. Open the admin dashboard and navigate to the **Membership** tab
2. Click the **Pending Approvals** sub-tab
3. Each pending application shows the applicant's email, the plan they applied for, the application date, and their form answers
4. Tap **Approve** to approve — the applicant receives an email and can proceed to payment
5. Tap **Reject** to open a rejection dialog, enter an optional reason, and confirm

> After approval, the subscription remains in `pending_payment` state until the member completes their payment. It becomes `active` once payment is confirmed.

## Feature 1.5: Setting Up the Application Form

Once you save a membership plan, an **Application Form** section appears in the plan edit screen. Here you can pick one form (created on the Forms page) and attach it to this plan's signup. It's exactly the same mechanism used to attach a form to a Check-in Config, so the same form definition can be reused for both check-in and membership signup.

| Item | Detail |
|------|--------|
| Supported flows | Both pay-first and apply-first (not limited to apply-first) |
| Available field types | Text, email, phone, number, select, date, textarea, image upload |
| Where answers are stored | Form Responses (the same response list used by the Forms feature), covered by the same personal-data protections as other form answers |
| Per plan | One form maximum (multiple forms cannot be attached at once) |

### How to Configure

1. Create the application form ahead of time on the **Forms** page (forms with target scope "Identity" or "Reservation" appear as candidates)
2. Create the membership plan and save it once
3. In the **Application Form** section of the edit screen shown after saving, select the form
4. The selection takes effect immediately

> **Not available immediately on creation.** Because the form binds to the saved plan's ID, it's a two-step process: save the plan first, then reopen the edit screen to attach the form.

### Migrating from the Old Intake Builder

Previously, only **Apply first** plans could collect intake fields, through a dedicated field builder limited to three field types (text, email, phone). That builder has been retired. **Plans that already had fields configured were automatically converted to the new form mechanism at release time — no action is required from the facility.** The converted form appears in the Application Form section and keeps working as before.

Server-side validation of required fields (missing answers, invalid email format) works the same way as before.

## Feature 1.6: Fee Payment Method (On-site)

For each membership plan, you can choose how the fee is collected. This is set with the **"Fee payment method"** dropdown on the plan edit screen.

| Option | Behaviour |
|---|---|
| **Online payment only** (default) | Both signup and renewal are billed automatically through Stripe, as before |
| **On-site only (no Stripe)** | Never goes through Stripe. The application stops in "awaiting payment" |
| **Applicant chooses** | The applicant picks online or on-site at signup |

Choosing "On-site only" or "Applicant chooses" reveals two extra fields:

| Field | Detail |
|---|---|
| Display label (up to 40 characters) | The name shown to both the applicant and the front desk. Defaults to "On-site payment" if left blank — override it to match how the facility actually collects payment (bank transfer, invoice, etc.) |
| Description (up to 80 characters) | Optional note for the applicant (e.g. "We will contact you separately.") |

> **Renaming the label does not change the mechanism.** Even if the label reads "Bank transfer", the front-desk action (recording a receipt — see [Feature 1.7](#feature-17-recording-an-on-site-fee-receipt)) is the same.

> **⚠️ The application stops at "awaiting payment" and does not activate until the front desk records a receipt. The same action is required for every renewal (monthly / yearly), too.** Unlike a Stripe-managed fee, nothing is charged automatically when the due date arrives, so every renewal needs a receipt recorded through [Feature 1.7](#feature-17-recording-an-on-site-fee-receipt). Leaving it unrecorded leads into the automatic lapse described in [Feature 1.75](#feature-175-automatic-lapse-of-on-site-fees).

## Feature 1.7: Recording an On-site Fee Receipt

A payment from an on-site-payable member (on-site only, or "applicant chooses" with on-site selected) can be recorded from two places. Both open the same shared receipt form used for on-site reservations and counter ticket-book sales.

### From the Members tab

1. Open the **Membership** tab → **Members** sub-tab
2. Click the **"Record payment"** button on the member's card
3. In the receipt dialog, enter the amount (defaults to the plan price, editable), the payment method (cash / bank transfer / other), the date and time received, and an optional note, then click **"Record receipt"**

The "Record payment" button only appears on a card whose status is approved-pending-payment, active, or past-due. It does not appear on a cancelled, force-cancelled, rejected, or expired card.

### From the Awaiting Payment tab

Uncollected fees are listed on the **Awaiting Payment** sub-tab. Unlike a status filter on the Members list, its badge shows the outstanding count next to the tab label without opening it — it's a collections work queue, the same idea as the Pending Approvals tab.

| Display | Meaning |
|---|---|
| Initial / not yet received | Applied, and no receipt has ever been recorded |
| N days left | N days until the next renewal date |
| N days overdue | N days past the renewal date (inside the grace window before lapse — see [Feature 1.75](#feature-175-automatic-lapse-of-on-site-fees)) |

Each row's **"Record payment"** button opens the same receipt dialog as the Members tab.

> **⚠️ This button never appears for a member Stripe is billing.** A member on an "applicant chooses" plan who selected online payment cannot have a receipt recorded from either screen, even though the plan itself supports on-site payment — Stripe is already collecting correctly, and recording it here would double-charge them. Check Stripe Dashboard for that member's payment status instead.

> A receipt cannot be recorded for a partial amount — the fee is always all-or-nothing. To settle only part of an outstanding balance (like a postpaid stay), use the receipt action on [Check-in History](checkin-history.md) instead.

## Feature 1.75: Automatic Lapse of On-site Fees

A fee that does not go through Stripe (on-site payment, or a ¥0 plan) is swept once a day at **2:00 AM JST** for expiry.

| Transition | When |
|---|---|
| Active → Past due | Once the renewal date has passed. **The member can still get in during this window** |
| Past due → Expired | Once a **7-day grace window** past-due has elapsed. **Keys and access are revoked** |

> **Why not cut them off immediately?** An on-site member can only pay by showing up. Locking them out on the renewal date itself would remove the very visit during which they would have paid — hence the 7-day grace window. No automatic reminder is sent to the member during this window; check the Awaiting Payment tab proactively instead.

> **A member Stripe bills is never touched by this sweep.** A subscription with a Stripe subscription ID keeps following Stripe's own retry / dunning behaviour regardless of this daily job.

## Feature 1.8: Enrollment Fee (one-time)

The **"Enrollment fee (one-time)"** field on the plan create / edit screen charges a **one-time amount on the first invoice only**, separately from the recurring price. Leave it blank or 0 to charge nothing.

| Item | Detail |
|---|---|
| When it is billed | **On the first invoice**, together with the (prorated) first month — one payment, not two |
| Apply-first plans | The post-approval payment includes both the first month and the enrollment fee |
| Changing it | Unlike the monthly price, it **can be changed after the plan is created** (it is a one-time line built at signup, not a Stripe recurring price) |
| Existing members | Unaffected. The fee only lands on the first invoice of a **new** application |
| Where it is shown | On the plan summary in the signup flow, and in the confirmation breakdown (first month / enrollment fee / total) |

### It cannot be set on a ¥0 plan

A free plan never goes through payment, so there is no path that could collect the fee. Saving one is rejected. If you need "¥0 per month with a one-time charge", model it as a one-time reservation plan instead of a membership.

### When it is waived

Today the fee is waived only when **the same application is resumed**. Re-joining after cancelling creates a new application, so **the enrollment fee applies again** — otherwise cancelling and re-joining would be a way to skip it.

> Indefinite free pause is a separate, planned feature. The value of pausing is precisely "no enrollment fee when you come back", which is why the fee lands first.

## Feature 1.9: Sales Status (Public / Unlisted / Closed)

The **"Sales status"** field on the plan create/edit screen controls whether the plan is listed on the member app and whether it accepts new signups.

| Status | Listed on member app | New signups via signup URL |
|--------|----------------------|------------------------------|
| **Public** (default) | Listed | Accepted |
| **Unlisted** | Not listed | Accepted (only for people who have the URL) |
| **Closed** | Not listed | Not accepted |

> **No status affects members who are already enrolled.** Their membership, keys, and billing continue as-is, and the member app keeps working for them. Sales status only controls who can *newly* join.

Every plan card always shows its signup URL (`member.unlockos.io/{facility-slug}?plan={planId}`). For Unlisted and Closed plans, a note about what happens if someone opens that URL is shown alongside it.

### When to use Unlisted

Use this for invite-only plans, corporate contracts, or staff-only plans — cases where you don't want the plan on the public list, but still want people who have the URL to be able to join.

### When to use Closed

Use this when you want to stop new signups only — for example, the plan is full or you're temporarily pausing enrollment. **If you want to remove a plan that still has members, use Closed first rather than retiring it** (see [Feature 2.7: Retiring and Reactivating a Plan](#feature-27-retiring-and-reactivating-a-plan)).

### How to Configure

1. Open the admin dashboard and navigate to the **Membership** tab, then create or edit a plan
2. In the **Sales status** dropdown, choose **Public**, **Unlisted**, or **Closed**
3. Save

---

## Feature 2: Configuring Quotas (Admin)

Quotas are set when creating or editing a membership plan in the **Membership** tab of the admin dashboard.

### Configurable Limits

| Field | Description | Reset Period |
|-------|-------------|--------------|
| **Monthly Visits** | Maximum number of check-ins per month | Monthly |
| **Daily Hours** | Maximum hours of usage per day | Daily |
| **Monthly Bookings** | Maximum time slot bookings per month (by count or by hours) | Monthly |

#### Monthly Bookings — Limit Type

Monthly bookings can be set to one of three modes:

| Choice | Behavior |
|--------|----------|
| **Unlimited** | No cap on monthly bookings or booking hours. The quota bar does not show a booking progress row. |
| **By count** | Sets a maximum number of bookings (slots) per month. |
| **By hours** | Sets a maximum total booking duration (hours) per month. |

Monthly Visits and Daily Hours are treated as unlimited when left blank.

### How to Create a Plan with Quotas

1. Open the admin dashboard and navigate to the **Membership** tab
2. Click the **Create Plan** button — you will be taken to a dedicated plan detail page
3. Enter basic plan information (name, price, billing interval, application flow, etc.)
   - The **Price** and **Billing interval** fields are labelled **(Not editable after creation)**. These cannot be changed after saving due to Stripe integration constraints
4. In the **Usage Limits** section, enter the desired limits

### Duplicating an Existing Plan

Instead of re-entering everything for a similar plan, copy an existing one.

1. In the admin dashboard, open the **Membership** tab and click the **duplicate icon** (left of the edit icon) on the plan you want to copy
2. The create-plan page opens pre-filled with the source plan's settings (price, billing interval, usage limits, check-in configurations, covered reservation plans, and so on)
3. The name is set to **{original plan name} (copy)** — change it as needed
4. Review the form and click **Create Plan** to save it as a new plan

What is NOT carried over:

| Item | Behaviour |
|------|-----------|
| **Sales status** | Always opens as **Closed**, even when the source plan is public, so a copy is never put on sale the moment it is created. Switch it in the form if you want the plan on sale |
| **Application form binding** | Not copied. Form bindings attach to a saved plan ID, so pick the form again from the edit screen after creating the plan |
| **Subscribers** | Not copied. The new plan starts with zero members |

> Clicking the duplicate icon saves nothing. Neither the source plan nor the new plan changes until you press **Create Plan**.

## Feature 2.5: Subscriber Count on Plan Cards

Each plan card in the Plans tab shows the current subscriber count as **{count} / {max}**. When no max member limit is set, it shows **{count}** (no cap). The count includes subscriptions in the `active`, `past_due`, `pending_approval`, and `pending_payment` statuses. Cancelled subscriptions are excluded.

## Feature 2.6: Reordering Plans (Display Order)

In the Plans tab, plan cards can be reordered freely by **drag and drop**, or with the **up/down buttons** on each card.

| Item | Detail |
|------|--------|
| How to reorder | Drag a card's handle, or tap the ↑ / ↓ button on a card |
| Where it applies | Both the admin Plans tab and **the member app's plan list use the exact same display order** |
| Saving | Reordering saves automatically — there is no separate save button |
| Scope | Retired plans ([Feature 2.7](#feature-27-retiring-and-reactivating-a-plan)) are excluded from reordering |

Previously there was no way to control display order — plans were always shown newest-first by creation date. Adding a single new plan would shift the whole order, and facilities had no way to keep their intended sequence.

> If a membership plan is added or removed elsewhere (another tab, another staff member) while you are reordering, saving your change fails and the list reverts to how it looked before you started. Reload the page and try reordering again.

## Feature 2.7: Retiring and Reactivating a Plan

The **Deactivate** button on a plan card retires the plan itself. This is a **more drastic action than Closed** ([Feature 1.9](#feature-19-sales-status-public-unlisted-closed)) — it immediately cancels every member's Stripe subscription and revokes their access and keys.

| Item | Detail |
|------|--------|
| When it can run | Only when the plan has **zero** members |
| What it does | Immediately cancels Stripe subscriptions, and revokes members' roles/facility membership and keys |
| Where it goes | Removed from the regular plan list and moved to the **"Retired plans"** section at the bottom of the screen |
| Undoing it | The **Reactivate** button in "Retired plans" restores the plan's configuration only |

### Plans with members cannot be retired

Attempting to deactivate a plan that still has one or more members is rejected with this message:

> This plan has {member count} member(s). Retiring it would force-remove all of them, so the action was blocked. To stop new signups only, edit the plan and set its sales status to "Closed".

**If you only want to stop new signups, use Closed (Feature 1.9) instead of retiring the plan.** Closed has no effect on existing members.

### After reactivating

A reactivated plan comes back with its sales status automatically set to **Closed** (so an accidentally-retired plan doesn't immediately go back on sale). To start accepting signups again, edit the plan and set its sales status to Public or Unlisted.

Reactivating only restores the plan's configuration. It does not restore the subscriptions or keys of members who were force-removed when the plan was retired.

## Feature 3: Overage Policy

Choose what happens when a member exceeds their quota.

| Policy | Behavior |
|--------|----------|
| **Block** | Check-ins and bookings are denied once the limit is reached. No additional charge. |
| **Charge** | Usage continues beyond the limit. Each overage is added as a Stripe Invoice Item on the next billing cycle. |

### Overage Fees (Charge policy only)

When the **Charge** policy is selected, overage fee fields appear.

| Field | Description | Example |
|-------|-------------|---------|
| Overage fee per visit | Charged for each check-in beyond the monthly visit limit | ¥500 |
| Overage fee per hour | Charged for each hour beyond the daily hours limit | ¥200 |
| Overage fee per booking | Charged for each booking beyond the monthly bookings limit | ¥300 |

Overage fees are billed in the plan's currency (JPY/USD). Leave a fee field blank to skip overage billing for that specific quota type.

## Feature 4: Membership Plans Excluded from the Booking Plan List

Plans created with `selected_plan_type='membership'` are not shown in the plan list on the booking page (Booking app). They are accessible only through the **Open Reservation Plan** button on the member app's Home screen. This prevents membership-only booking slots from appearing alongside general reservation plans.

## Feature 5: Quota Bar (Member App)

On the home screen of the Member App, a quota bar is displayed for each active limit on the member's plan.

### Displayed Information

- **Label**: Monthly Visits / Today's Usage / Monthly Bookings
- **Count**: Used / Limit (e.g., `2 / 5`)
- **Progress bar**: Visual indicator of usage percentage
  - Teal (normal): below 80% used
  - Amber (warning): 80%–99% used
  - Red (limit reached): 100% used

### Overage Charge Note

When the overage policy is set to **Charge**, the following note appears below the quota bars:

> Overage charges apply when limits are exceeded

## Feature 6: Covered Reservation Plans (Free-Quota Scope)

The membership plan edit form includes a **Covered reservation plans** multi-select inside the **Booking Limits** section. The regular reservation plans selected here are covered by this membership plan's free quota.

> **This setting applies to walk-ins (front desk / on-site check-in) too, not just the booking service.** Walk-in free-tier eligibility used to be managed per Check-in Config; it is now unified with this plan-level setting.

| Selection state | Behavior for bookings | Behavior for walk-ins |
|-----------------|------------------------|------------------------|
| None selected (default) | All reservation plans are covered — members get the free quota on any plan they book (legacy behavior) | Not decided at the plan level — falls back to the **Check-in Configurations** field described below |
| One or more selected | Only the selected plans are covered. Plans not on the list are charged at the regular rate, even for members | Free only if the covered plan (free) is part of that Check-in Config; otherwise charged |

> **Non-members are never locked out.** Setting covered reservation plans does not restrict who can book — non-members can still book any plan at the regular rate. This setting only controls whether a booking is *free*, not whether it can be *made*.

### How to Configure

Open the admin dashboard and navigate to the **Membership** tab, then create or edit a plan. In the **Booking Limits** section, use the two multi-selects below as needed (multi-select, searchable):

1. **Covered reservation plans (free for members)** — plans selected here become **¥0 for members** (covered by the free quota). Applies to both bookings and walk-ins
2. **Covered reservation plans (member-priced, charged normally)** — plans selected here appear on the member app's "Reservation Plans" card, but are **charged at the regular rate**. This field does not affect walk-in free-tier eligibility

If both are left empty, bookings fall back (legacy behavior) to **all reservation plans covered for free**; walk-ins fall back to the Check-in Configurations field described next.

Saving shows the selected plans as tags in each section. The same plan cannot be selected in both fields (adding it to one automatically removes it from the other).

### Constraints on Covered Plans

- The selection candidates only include **active reservation plans belonging to this facility**. Plans from other facilities or inactive plans are excluded from new selections
- If a linked plan is later deactivated, its name still appears as a tag on the existing selection, but it will not appear as a candidate for new links
- On save, any plan ID that belongs to another facility or no longer exists is automatically dropped, and a warning — "Some plans could not be linked because they no longer exist in this facility" — appears at the top of the screen (the save itself still succeeds)

### Check-in Configurations (member page entry points)

**Whether the member page shows a check-in button at all is decided by this field together with "Covered reservation plans (free for members)".** It is always expanded on the membership plan edit screen.

Resolution order:

1. If a Check-in Configuration's billing plan is one of the plans selected under "Covered reservation plans (free for members)", **that configuration becomes the member page entry point**
2. If none can be derived that way (nothing selected, or the selected plans are not the billing plan of any Check-in Configuration), **the configurations listed in this field are used instead**
3. **If neither resolves, members on this plan get no check-in button on the member page at all**

> **⚠️ Selecting "Covered reservation plans (free for members)" alone is not always enough.** If the plan you selected is not the billing plan of any Check-in Configuration, the price becomes free for members but no entry point appears. In that case, name the Check-in Configuration directly in this field.

This field is walk-in only and does not affect the booking service.

- Pricing (whether the member pays) follows the same order. Once a "covered for free" plan is selected *and* it resolves to a Check-in Configuration, pricing moves to the plan-level decision
- Facilities that used to split member tiers across several Check-in Configs can consolidate them into **one entrance** after migrating to covered reservation plans. Consolidating brings that entrance's max-capacity setting closer to the facility's real simultaneous occupancy (you no longer need one entrance per member tier). It also means the plan-selection step during check-in is skipped automatically on any day a member's free plan resolves to exactly one candidate

### How the Free Quota Applies

When a member books a covered reservation plan:
- If **Monthly Bookings** (by count or by hours) is set above, the free quota applies within that limit
- If Monthly Bookings is **Unlimited**, the booking is always free
- Exceeding the limit follows **Feature 3: Overage Policy** (block or charge)

When a member books a plan that is not covered, the standard guest price applies as-is (the free quota is not consumed). See [Member & Subscription Bookings](guest-member-booking.md) for how this appears on the guest-side confirmation screen.

---

## Configuration Examples

### Example 1: Standard Coworking Plan

Allow up to 20 visits and 8 hours per day; block when exceeded:

- Monthly Visits: `20`
- Daily Hours: `8`
- Monthly Bookings: (blank)
- Overage Policy: **Block**

### Example 2: Flex Membership

Allow up to 10 visits; charge ¥500 per extra visit:

- Monthly Visits: `10`
- Daily Hours: (blank)
- Monthly Bookings: (blank)
- Overage Policy: **Charge**
- Overage fee per visit: `500`

### Example 3: Studio Class Membership

Limit to 4 time slot bookings per month; block further bookings:

- Monthly Visits: (blank)
- Daily Hours: (blank)
- Monthly Bookings: **By count** → `4`
- Overage Policy: **Block**

---

## Frequently Asked Questions

### Q: When do quotas reset?

Monthly quotas reset automatically on the 1st of each month at 00:00 in the facility's timezone. Daily quotas reset every day at 00:00. No manual action is required.

### Q: If multiple limits are set, which one triggers the restriction?

Any one of the limits reaching its quota is enough to trigger the restriction. For example, if both monthly visits and daily hours are set, whichever is reached first will block (or charge) further usage.

### Q: When are overage charges billed?

Overage charges are recorded as Stripe Invoice Items each time a limit is exceeded. They are consolidated into the member's next regular invoice (monthly or yearly billing cycle).

### Q: The member's quota bar is not visible in the app. Why?

The quota bar only appears when at least one quota limit is active. If Monthly Bookings is set to **Unlimited** and Monthly Visits and Daily Hours are both blank, no quota bar is shown.

### Q: If I update a plan's quota limits, when does the change take effect?

Updated limits take effect after the next quota reset cycle. The current usage count is carried over; only the limit threshold changes.

### Q: If I add or change covered reservation plans, does it apply to existing members immediately?

Yes. Covered-plan links take effect the moment you save — no backfill is required. Members with an already-active subscription get the new configuration starting with their next booking.

### Q: What happens if I don't select any covered reservation plans?

All reservation plans are covered (the legacy, backward-compatible behavior). Only narrow down the covered reservation plans if you want to limit the free quota to specific plans.

### Q: Does the walk-in (direct check-in) free tier also follow covered reservation plans?

Yes. Selecting one or more "covered for free" plans applies that setting to both bookings and walk-ins. A membership plan with none selected — or one whose selected plans do not resolve to any Check-in Configuration — falls back to the "Check-in Configurations (member page entry points)" field for walk-ins.

### Q: Is the application form only available on apply-first plans?

No. The **Application Form** section that appears after saving a plan works for both pay-first and apply-first flows. It used to be an apply-first-only field builder; it's now unified with the same form mechanism used by check-in (see [Feature 1.5](#feature-15-setting-up-the-application-form)).

### Q: If I set a plan to Unlisted or Closed, do existing members lose access?

No. Sales status only affects people who are not yet members. Existing members keep their subscription, keys, billing, and access to the member app exactly as before.

### Q: I can't retire (deactivate) a plan that has members

Plans with one or more members cannot be retired, because doing so would force-remove all of them. If you only want to stop new signups, set the sales status to Closed instead. If you do need to retire the plan itself, you can once it has zero members.

### Q: Can I undo retiring a plan?

Yes. Use the **Reactivate** button in the "Retired plans" section at the bottom of the plan list. Only the plan's configuration comes back — subscriptions and keys of members who were force-removed when the plan was retired are not restored. A reactivated plan comes back Closed, so edit it and set the sales status to Public or Unlisted to start accepting signups again.

### Q: An on-site-payable member has no "Record payment" button

First check that the plan's "Fee payment method" is set to on-site-capable (on-site only, or applicant chooses). Even when it is, the button is hidden if that particular member actually chose online payment (Stripe) — this is deliberate, to avoid double-charging. The button also never appears for a cancelled, force-cancelled, rejected, or expired member.

### Q: What happens if an on-site fee goes uncollected?

Once the renewal date passes, the member automatically becomes "past due" — access still works during this window. After a 7-day grace period past due, the member automatically becomes "expired" and keys/access are revoked (see [Feature 1.75](#feature-175-automatic-lapse-of-on-site-fees)). No automatic reminder email is sent, so check the **Awaiting Payment** tab regularly to collect.

### Q: Can I record a partial on-site fee payment?

No. A fee receipt only records an amount that exactly matches what is due — partial payments are not supported. If you need to settle part of an outstanding balance, such as a postpaid stay, use the receipt action on [Check-in History](checkin-history.md) instead of the membership fee flow.

---

## Troubleshooting

### Member is blocked even though quota appears not exceeded

Check the following:

1. Review all quota bars on the member app home screen — daily hours and monthly visits/bookings are tracked separately
2. Confirm the membership subscription has not expired (check "Valid Until" on the home screen)
3. If the issue persists, contact the facility admin to review the plan configuration

### Quota bar does not appear in the member app

- Monthly Bookings is set to **Unlimited** and Monthly Visits and Daily Hours are both blank. The bar is not shown when no limits are active.
- Check the plan's Usage Limits settings in the admin dashboard and add at least one limit value.

### A member is charged the regular rate on a specific plan

1. In the admin dashboard, check the **Covered reservation plans** setting for that membership plan and confirm whether the plan in question is selected
2. If one or more covered reservation plans are selected, any plan not on the list is charged at the regular rate by design — this setting exists to narrow the free-quota scope
3. To make the free quota apply to all plans again, clear every selection in Covered reservation plans (none selected = all plans covered)
4. Changes take effect immediately after saving — reload the page if it does not appear to apply

### A member is charged the regular rate on a walk-in (direct check-in)

1. Check whether that membership plan's **Covered reservation plans (free for members)** includes the plan tied to the Check-in Config being used
2. Confirm that the selected plan **is the billing plan of that Check-in Configuration**. Once it resolves, pricing moves to the plan-level decision
3. If no "covered for free" plans are selected, check whether that Check-in Configuration is listed in the "Check-in Configurations (member page entry points)" field instead

### The member page shows no check-in button at all

No entry point resolves for that membership plan. Check, in order:

1. Whether a plan selected under **"Covered reservation plans (free for members)"** is the billing plan of some Check-in Configuration. If it is, that configuration becomes the entry point automatically
2. If not, **name the Check-in Configuration directly in "Check-in Configurations (member page entry points)"**. Selecting covered reservation plans alone does not create an entry point
3. Whether the named Check-in Configuration has been deactivated

---

## Stripe Customer Portal Setup (Required for Facility Owners)

To allow members to change their payment method and download receipts, you must enable the **Customer Portal** in your Stripe Dashboard.

### Setup Steps

1. Log in to [Stripe Dashboard](https://dashboard.stripe.com/)
2. Go to **Settings** → **Billing** → **Customer portal**
3. Configure the following:

| Setting | Value | Reason |
|---------|-------|--------|
| **Payment methods** | ✅ Enabled | Allow members to add, update, or remove cards |
| **Invoice history** | ✅ Enabled | Allow members to view and download receipt PDFs |
| **Subscriptions > Cancel subscriptions** | ❌ Disabled | Cancellation is handled through UnlockOS |
| **Subscriptions > Switch plans** | ❌ Disabled | Plan changes are managed through UnlockOS |

4. Click **Save**

### Important Notes

- This setting applies to your **entire Stripe account** (not per-facility)
- Test mode and live mode require separate configuration
- Once configured, a "Manage Cards & Invoices" button appears on the member app's Payment History page
- Clicking the button opens Stripe's portal; members return to the app when finished

### If Customer Portal is Not Configured

If a member clicks the button before setup is complete, Stripe will return an error. Make sure to complete the above configuration before publishing your membership plans.

---

## Related Pages

- [Member Signup](member-signup.md)
- [Member Management](members.md)
- [Member Home Screen](member-home.md)
- [Member & Subscription Bookings](guest-member-booking.md)
- [Time Slot Booking Help (Member)](timeslot-booking-member.md)
- [Time Slot Booking Plan Configuration (Admin)](timeslot-booking-admin.md)
- [Booking Management Dashboard](booking.md)
- [Blacklist Management](blacklist.md)
- [Ticket Books](ticket-books.md)
- [Check-in History](checkin-history.md)

---

Last updated: 2026-09-08 - Documented on-site membership fee payments (fee payment method setting, recording receipts from the Members / Awaiting Payment tabs, the Stripe-billed exclusion, and automatic lapse of on-site fees) (Epic #3421 / #3424 / #3425 / #3426)

Previously updated: 2026-09-02 - Documented sales status (public/unlisted/closed), plan reordering, and retiring/reactivating plans (#3202, #3203, #3204, #2772, #3068)
