Complete reference for the one-off purchase flow (Track 3) — day passes and other single-transaction products. Uses Stripe PaymentIntent for immediate charges and creates OfficerRnD day passes for kiosk check-in.
Track 3 shares the same Cloudflare Worker as Track 1 (membership subscriptions) but uses Stripe PaymentIntents for one-off charges instead of SetupIntents for subscriptions. The same Webflow CMS template page serves both flows, toggled by a "Purchase Type" CMS field with conditional visibility.
Eleven steps take a visitor from landing on a purchase page to holding an active day pass.
Visitor browses to a product page on labourtemple.com (e.g. /memberships/day-pass). The CMS "Purchase Type" field is set to "One-Time", which shows the purchase form instead of the subscription checkout form via conditional visibility.
Webflow CMSpurchase.js detects the product slug from the URL path (e.g. "day-pass"), fetches product data from the Worker's GET /products endpoint, and renders a flat-price order summary. No pro-rating or initiation fees.
Purchase JSNative Webflow fields collect: first name, last name, email, phone, company name, referral source, and optional notes. The Stripe Payment Element (mode: payment) collects card or bank account details.
Webflow + StripeThe site script calls window._validate() to check all required fields. If validation fails, fields are highlighted and submission is stopped.
The script calls elements.submit() to securely tokenize the payment method with Stripe.
Form data and product slug are sent to POST /create-purchase. The Worker creates or finds an OfficerRnD member, creates or finds a Stripe Customer, applies promo if provided, and creates a PaymentIntent. Returns clientSecret, paymentIntent ID, and memberId.
Cloudflare WorkerThe site script calls stripe.confirmPayment() with the client secret. Stripe charges the card or bank account immediately.
The site script calls window._complete(memberId, paymentIntentId, slug, customerName), which sends data to POST /complete-purchase.
The Worker verifies the PaymentIntent succeeded, then creates a day pass via POST /passes with explicit parameters: member, count: 1, type: "hotdesk", validFrom/validTo (today), intervalLength: "once", grantActiveStatus: true. The pass appears in the member's Day Passes tab for kiosk check-in.
OfficerRnDThe Worker sends a branded purchase confirmation email (with receipt URL, payment method, date) to the customer and a plain-text notification to the team via MailerSend.
MailerSendOn success, the user is redirected to /purchase-confirmation.
WebflowFive services work together to power the purchase system — the same Worker used for Track 1 subscriptions.
Hosts product pages (CMS collection) and embeds the purchase form. The CMS "Purchase Type" field toggles between checkout (subscription) and purchase (one-off) forms via conditional visibility.
Shared with Track 1. Orchestrates the purchase: creates OfficerRnD members, Stripe customers, PaymentIntents, day passes, and sends confirmation emails. Also serves the external purchase JS.
Processes card and ACH payments via PaymentIntents. No subscriptions or recurring billing. Charge receipt URL is included in the confirmation email.
Stores member records and day pass allocations. Day passes appear in the member's profile for kiosk check-in at the front desk.
Sends branded purchase confirmation emails with receipt details to the customer and plain-text notifications to the team.
Products are defined in PRODUCT_CONFIG inside the Worker. Unlike PLAN_CONFIG (subscriptions), products have no initiation fees, no pro-rating, and no auto-promo system.
| Product Name | Slug | Price | OfficerRnD Plan ID | Terms |
|---|---|---|---|---|
| Day Pass | day-pass | $50 | 66b399ef3de7dbab92b5c985 |
/legal/membership-terms |
Day passes are created via OfficerRnD's POST /passes endpoint. This is an undocumented API endpoint (not in the API reference, but documented in help center articles and confirmed working).
| Field | Value | Notes |
|---|---|---|
member | OfficerRnD member ID | Find-or-create by email |
count | 1 | One pass per purchase |
type | "hotdesk" | Must be "hotdesk" (not "membership") for correct display |
validFrom | Today midnight UTC | e.g. 2026-04-03T00:00:00.000Z |
validTo | Today midnight UTC | Same as validFrom for single-day pass |
intervalLength | "once" | Non-recurring |
grantActiveStatus | true | Required for kiosk check-in |
passesValidityPeriod.intervalCount must be set to a non-zero value (currently 12 months) or passes will have zero validity.
npx wrangler deployThree locations contain purchase logic:
npx wrangler deploywrangler deploy (5 min cache)wrangler deployTrack 1 (subscriptions): Uses SetupIntent to confirm the payment method first, then creates a subscription. The charge happens via the subscription's first invoice.
Track 3 (purchases): Uses PaymentIntent to charge immediately. No subscription. The Stripe Elements mode is set to payment with a fixed amount.
The Memberships CMS template page contains both the checkout form (Track 1) and the purchase form (Track 3). Webflow conditional visibility on the "Purchase Type" Option field controls which is shown:
Both site scripts self-guard: stripe-payment.js checks for #checkout, stripe-purchase.js checks for #purchase. Only one script initializes Stripe.
Unlike Track 1 (which uses a CMS data-plan attribute), Track 3 detects the product slug from the URL path:
var slug = location.pathname.split('/').filter(Boolean).pop() || '';
For /memberships/day-pass, the slug is day-pass. This is matched against PRODUCT_CONFIG keys in the Worker.
After confirming the PaymentIntent succeeded, the Worker extracts receipt details from the Stripe Charge object:
Extraction failure is non-critical and logged as a warning.
Check #purchase element exists (conditional visibility), window._S defined in embed, site script applied and published.
Product slug from URL doesn't match PRODUCT_CONFIG key. Check the URL path.
Check Worker logs for pass creation warnings. Verify plan's passesValidityPeriod.intervalCount is not 0. Ensure type is "hotdesk".
Customer name not passed from frontend. Verify _complete() sends 4th argument (customerName).
Check the CMS "Purchase Type" field value. "Subscription" shows checkout form, "One-Time" shows purchase form.
Browser Console for JS errors · Network tab for POST requests · Cloudflare Logs for Worker errors · Stripe Dashboard > Developers > Logs · MailerSend Dashboard > Activity