Custom booking system for Fat Cat Fab Lab's two spaces (Main Space + Event Space).
Live preview: https://harrison-f.github.io/fcfl-booking-preview/
index.html— Booking form (light/dark mode, responsive, dynamic pricing)apps-script.js— Google Apps Script backend (sheet management, Stripe, emails)
- Fill out booking form → confirmation email sent
- Board gets notification email
- Board approves in Google Sheet (Status → "Approved")
- Member gets approval email with Stripe payment link
- Member pays (deposit + hosting fee if applicable)
- 72 hours after event → $50 deposit auto-refunded
- Member gets "deposit refunded" email
- New row appears in "Event Bookings" sheet
- Review the request
- Change Status to "Approved" (or "Denied")
- Everything else is automatic
- If rules broken → run
captureDeposit(rowNumber)in Apps Script to skip the refund
- Free events: $50 refundable deposit only
- Paid events: $50 deposit + $20/hr hosting fee
- Deposit auto-refunds 72 hours after event date
- Open your Google Sheet → Extensions → Apps Script
- Delete any existing code in
Code.gs - Paste the contents of
apps-script.js→ Save
- In Apps Script editor → Project Settings (gear icon) → Script Properties
- Add property:
STRIPE_SECRET_KEY= your Stripe secret key - Run
testStripeConnection()to verify (should log ✅)
- Run
setupTriggers()from the function dropdown - This creates three triggers:
- onStatusChange — installable onEdit (fires approval flow with full permissions)
- checkPaymentStatus — every 2 hours (polls Stripe for payment confirmation)
- autoRefundDeposits — every 6 hours (refunds deposits 72hrs after events)
- Deploy → New deployment → Web app
- Execute as: Me | Who has access: Anyone
- Copy the Web App URL
- Update
APPS_SCRIPT_URLinindex.htmlwith that URL
- Replace the test Stripe key in Script Properties with your live key (
sk_live_...) - Host
index.htmlon fatcatfablab.org
| Col | Header | Notes |
|---|---|---|
| A | Timestamp | Auto-filled |
| B | Name | |
| C | ||
| D | Event Name | |
| E | Status | Dropdown: Pending / Approved / Completed / Denied / Cancelled |
| F | Description | |
| G | Space | Main Space or Event Space |
| H | Date | |
| I | Start Time | |
| J | End Time | |
| K | Duration (hrs) | Auto-calculated |
| L | Free Event? | Yes / No |
| M | Hosting Fee | $0 for free events, $20×hrs for paid |
| N | Deposit | Always $50 |
| O | Payment Status | Auto-updated by script |
| P | Deposit PI ID | Stripe Checkout Session ID |
| Q | Fee PI ID | Stripe Payment Intent ID |
| R | Notes | Optional |
Charge + refund: the full amount (deposit + any fees) is charged upfront via Stripe Checkout. The $50 deposit is automatically refunded 72 hours after the event. If rules are broken, run captureDeposit(rowNumber) to mark the deposit as retained (skips auto-refund).
- Form submits but no row: Check the Apps Script web app URL in index.html
- Approval email not sending: Ensure
setupTriggers()was run (creates installable trigger with full permissions) - Stripe errors: Check Payment Status column — errors are logged there
- Key errors: Verify key in Project Settings → Script Properties; run
testStripeConnection()