Skip to main content

Events & Shops

How to configure the Flourish Liminal managed package for paid tickets, donations, products, and bookable time slots.

Overview

Flourish Liminal is a Salesforce managed package that gives you a flexible, lightweight way to run any of these:

  • Ticket sales for an event, with quantity limits (e.g. 50 general admission seats).
  • Product purchases with stock counts.
  • Time-slot booking — visitors pick a date/time from a calendar (think appointment booking, classes, tours).
  • Paid registrations with online card or bank payment via Braintree.
  • Recurring donations if you have NPSP installed.

Every purchase produces an Opportunity in Salesforce, attached to a matched or newly created Contact (and Account, if you have NPSP).

This guide covers everything except the volunteer signup flow. For that, see Volunteers. The two are independent — you can use either, both, or neither.


Before You Start

You need:

  • The Flourish Liminal managed package installed.
  • A Braintree account (production or sandbox) if you want to take payments.
  • Permission to create custom metadata records, edit Lightning pages, and manage permission sets and sharing rules.
  • (Optional) NPSP for the recurring-donation features. NPSP is detected automatically; without it, the recurring path is silently skipped.

Step 1 — Configure the org-wide settings

Liminal reads a single custom metadata record to find its Braintree credentials and other defaults.

  1. Go to Setup > Custom Metadata Types > FL Liminal > Manage Records.
  2. Click New and fill in:
    • Label and FL Liminal Name: global (case-sensitive — the package looks up getInstance('global')).
    • Braintree Token — paste your Braintree API key (Bearer-format).
    • Braintree Sandbox Mode — check this for testing; uncheck for production. The package routes all callouts to the sandbox or production endpoint based on this flag.
    • Completed Order Opp StageName — the Opportunity StageName Liminal should write when a payment clears (e.g. Closed Won). Defaults to Closed Won if blank.
    • Customer Support Email — shown on the checkout page so customers know who to contact.
    • Payment Mailing Address — shown on the checkout page as the "mail a check" address.
  3. Save.

Note: The package errors out with "No org-wide settings have been configured for Flourish Liminal" if this record is missing. You only ever need one record, named global.


Step 2 — Assign the permission set

The package ships with Liminal Admin, which grants read/edit on every Liminal custom field plus object-level permissions on the three custom objects.

  1. Go to Setup > Permission Sets.
  2. Open Liminal Admin > Manage Assignments > Add Assignments.
  3. Add yourself and anyone else who will be configuring offerings.

Note: This permission set does not grant guest user access. For public-facing pages, see Step 7.


Step 3 — Plan your data: engagements, offerings, availabilities

Liminal's three building blocks:

ConceptSalesforce objectThink of it as
EngagementCampaignThe event, course, or campaign that groups everything (e.g. Spring Gala 2026, Yoga Classes — Summer).
OfferingLiminal OfferingA thing within the engagement that someone can buy or book (e.g. General Admission, VIP Ticket, Drop-in Yoga Class).
AvailabilityLiminal AvailabilityThe inventory or schedule for an offering. Three flavors below.

The Availability record type decides what the offering behaves like:

  • Stock — fixed-quantity inventory. Use for tickets, products, anything counted.
  • Slot — scheduled time blocks the visitor picks from a calendar. Use for appointments, classes, tours.
  • Hybrid — both. A class with 12 seats on a specific Saturday from 10 a.m. to noon.

Step 4 — Create an engagement (Campaign)

  1. Campaigns tab > New.
  2. Fill in:
    • Campaign Name — public title.
    • Active — must be checked for the engagement to appear in the storefront.
    • Description, Start Date, End Date — standard.
    • Event Image URL — public URL to a hero image.
    • Address Street / City / State / Postal Code — display fields.
    • Lim Status, Lim Tags — free-form metadata you can use for reporting filters.
    • Lim TZ Name / Lim TZ Offset — informational fields for the engagement's timezone.
    • Lim Customer Detail Template — optional template string controlling which fields the customer-details form on checkout renders. Leave blank to use the default form.
  3. Save.

Step 5 — Create offerings and availabilities

5.1 Stock-style offering (tickets, products)

  1. From your Campaign, scroll to Liminal Offerings > New.
  2. Fill in:
    • Name (internal) and Label (public — leave blank to mirror Name).
    • Description (rich text supported).
    • Image Landing / Thumbnail — public URLs.
    • Price — per-unit price in your default currency. Leave blank for free.
    • Engagement — auto-set from the Campaign.
  3. Save the offering.
  4. From the offering, create a Liminal Availability with record type Stock:
    • Quantity — total available (e.g. 100).
    • Save.

Now 100 units of inventory are available. The package automatically decrements as people add to cart (Claimed) and as orders complete (Ordered). You can create more Stock Availabilities under the same Offering and the system sums them — useful when you receive shipments in batches.

5.2 Slot-style offering (appointments, classes)

  1. Create the offering as above. Set Slot Value Type = Date (whole-day slots) or Datetime (with hours). Set Slot TZ (e.g. America/New_York) and Slot Duration if you want fixed-length slots (in minutes for Datetime mode, days for Date mode).
  2. Allow Multiple Slots — check if a single visitor can book several slots in one order.
  3. Weekend Availability — set to Unavailable to auto-skip Sat/Sun in the calendar.
  4. Save.
  5. Create Liminal Availability records with record type Slot:
    • Slot Open/Close: Open for windows when bookings can happen, Close for blackouts (holidays, lunch breaks).
    • Start Datetime / End Datetime — the window. Both must fall inside the Campaign's Start/End dates (a validation rule enforces this).
    • Max Bookings — how many overlapping bookings the window can hold.
  6. Save each.

The calendar component subtracts the Close windows from the Opens, then emits fixed-length slots of Slot_Duration__c minutes within whatever remains. Already-booked selections from other orders are also subtracted, so visitors don't see slots that are full.

5.3 Hybrid offering

Create an Availability with record type Hybrid and fill in both Quantity__c and the slot Start/End times. Useful for "a workshop with 12 seats on this exact date."


Step 6 — Publish the storefront page

Liminal ships three main public LWCs you can mix and match on a Lightning App Page or Experience Cloud page:

Component (in App Builder)What to use it forRequired properties
Liminal: Ticket StorefrontStock-style purchasing UI with +/- buttons.engagementId, orderId
Liminal: CalendarSlot-style booking UI with calendar grid.offeringId, orderId
Liminal: CheckoutFinal payment + customer-details step.orderId

A typical end-to-end purchase page looks like one of:

  • Tickets: Storefront → Checkout
  • Slot booking: Calendar → Checkout
  • Mixed: Storefront + Calendar (multiple offerings) → Checkout

To publish:

  1. Open Lightning App Builder > New Page (App Page or Community Page).
  2. Drag the components on. In each component's properties panel, set the engagementId / offeringId and a shared orderId. The orderId is a free-form string — typically you generate it client-side or use a Flow that sets it before opening the page.
  3. Save and Activate the page.

Generating the Order ID

The Order ID is the cart key — every Selection and the eventual Opportunity share it. Approaches:

  • Hardcode for testing: paste any string (TEST-123) into the component property.
  • URL parameter: pass ?orderId=... and bind it via a small wrapper LWC or a Flow.
  • Auto-generate via Flow: a screen flow that calls Crypto.generateAesKey or any random-string generator before opening the storefront. The volunteer flow does this server-side; for the storefront you typically do it client-side or in the URL.

A single visitor session should keep the same Order ID across Storefront → Calendar → Checkout — that is what stitches selections into one cart.


Step 7 — Configure Experience Cloud (public sites)

If your storefront lives on a public site rather than inside Salesforce:

  1. Site published with the page hosting the Liminal components.
  2. Guest User Profile for the site grants:
    • Read on Campaign, Liminal Offering, Liminal Availability.
    • Create / Edit / Delete on Liminal Selection.
    • Create / Edit on Contact, Opportunity, and Account.
  3. Sharing rules / sharing sets that expose your active Campaigns, Offerings, and Availabilities to the guest user. (Default org-wide is Private for most of these objects.)
  4. CSP Trusted Sites — the package adds FL_ArqueraLiminal (legacy asset host). If you serve images or scripts from other domains, add them in Setup > CSP Trusted Sites.
  5. Remote Site Settings — the package ships FL_Braintree (production) and FL_BraintreeSandbox; both should be Active. They authorize the server-to-Braintree callouts.

Test the full flow in an incognito browser window using a Braintree sandbox card number (e.g. 4111 1111 1111 1111) before going live.


Step 8 — How payments work

The Liminal: Checkout component:

  1. Loads the order's Selections via the orderId.
  2. Calls Braintree to get a client token for the embedded payment form (uses Braintree_Token__c + the sandbox flag from your global custom metadata record).
  3. Renders the payment form (card or bank account, depending on what you have enabled).
  4. On submit, sends the payment nonce + amount to Braintree.
  5. On success, Liminal:
    • Finds-or-creates the Contact (fuzzy match by name + email + phone + address via SOSL; if NPSP is installed, alternate emails are checked too).
    • Inserts or updates an Opportunity with Lim Order ID = your order id, Amount = sum of Price Final across selections, StageName = the value from Completed_Order_Opp_StageName__c (or Closed Won if blank), CloseDate = today.
    • Flips all the order's Selections to status Ordered.

If payment succeeds but Salesforce DML fails afterward, the checkout shows a recovery message asking the customer to email support with the order id — the charge stands, the Salesforce side can be fixed manually.

Supported payment methods

MethodStatus
Credit / debit cardFully wired and tested.
ACH (US bank account)Tokenization is implemented in Apex, and the checkout UI default config has it enabled. Verify with a sandbox before exposing.
Mail a checkDisplay-only — the LWC shows the Payment Mailing Address from your config, but there is no automated reconciliation.
Pay later (unpaid Opportunity)Toggle paylater on the checkout component to create an open Opportunity without charging. Useful for invoicing workflows.

Recurring donations

If your org has NPSP installed:

  • The checkout's vaultPaymentMethod path stores the card token and creates an npe03__Recurring_Donation__c record.
  • Existing Pledged Opportunities for the same Account are withdrawn first to avoid duplicates.
  • Frequency, amount, and payment method are stamped on the recurring donation.

If NPSP is not installed, the recurring path quietly returns "Recurring Donations (npe03) package is not installed; skipping recurring setup." — no error, no record created.


Step 9 — What records show up after a sale

For each completed order:

RecordWhere to find it
ContactMatched or created by the fuzzy lookup. Look on the Contact tab — search by email.
AccountIf NPSP, the household Account auto-created. Otherwise the Contact's Account (may be null in non-NPSP orgs).
OpportunityNamed Liminal Order #<orderId> (or Volunteer – <Event> – <Role> – <email> from the volunteer flow). Amount = total paid. Lim Order ID field carries the cart id.
Liminal SelectionsOne per line item. Status = Ordered, with the price and (for slot offerings) the booked Start/End times.

Reports:

  • Opportunities WHERE Lim Order ID starts with "LIM-" → all paid Liminal orders.
  • Liminal Selections WHERE Status = "Ordered" AND CreatedDate = THIS_WEEK → this week's bookings/sales.
  • Liminal Offerings WHERE Engagement = <Campaign> → inventory dashboard for an engagement.

Step 10 — Inventory math (how rollups work)

The package maintains several rollup fields automatically.

On Liminal Offering:

  • Quantity Provided = sum of Quantity across all Stock-type Availabilities. Maintained by the Availability trigger.
  • Quantity Claimed = count of Selections in status Claimed (i.e. in someone's cart).
  • Quantity Ordered = count of Selections in status Ordered (paid).
  • Quantity Consumed = Claimed + Ordered (formula).
  • Quantity Available = Provided − Consumed (formula).

Slot-style offerings have a parallel set (Slots Provided, Slots Claimed, Slots Ordered, Slots Consumed, Slots Available).

Warning: Carts that get abandoned still hold inventory as Claimed. There is no automatic cart-expiration today. If you see your Quantity Available looking lower than expected, query for stale Claimed Selections and delete them — they will roll off the count automatically.


Step 11 — Customizing what the customer sees

Branding

  • Replace the bundled images and fonts in the liminal_static static resource bundle. Most assets are exposed via ${STATIC}/... URLs in the LWCs.
  • Tweak Lightning Design System theme tokens at the Experience Cloud or community level to recolor buttons, headers, etc.

Customer detail form

The set of fields shown on checkout is driven by Campaign.Lim_Customer_Detail_Template__c. The template is parsed at runtime — you can vary the required fields per engagement (e.g. require shipping address for product orders, only require email for donations).

Confirmation email

There is no confirmation email shipped for the paid checkout flow (the included Volunteer_Confirmation_Email_Autolaunched_Flow is for the volunteer side). To send a receipt, build a record-triggered Flow on Opportunity that fires when StageName changes to your Completed_Order_Opp_StageName__c value, and send an emailSimple action with your own template.


Common questions

Can a single page combine ticket sales and slot booking? Yes — drop both Liminal: Ticket Storefront and Liminal: Calendar on the same page, give them the same orderId, and Checkout will charge the combined total.

What if Braintree is down during checkout? The package returns "The payment processor appears to be down. Wait a few minutes, refresh the page, then try again." No partial records are written — the Selections stay Claimed and the cart can be retried.

Can I refund through Liminal? No automated refund flow. Issue the refund directly in Braintree, then either delete the affected Selections or move the Opportunity to a refund stage of your choosing.

Can I use my own payment processor? The Apex is structured to allow it — Lim_PaymentUtility.checkoutOrder switches on paymentProcessor. Only 'Braintree' is wired today; adding Stripe or another would require a new utility class on the same pattern as Lim_BraintreeUtility.

Why does the calendar show 9 months of slots? That is the package default (CALENDAR_MAX_DATE = today + 274 days). Currently hardcoded; a future release will make it configurable.

How do I clean up abandoned carts? Either schedule a batch Apex job in your org to delete Selections in Claimed status older than N days, or build a Flow with a scheduled trigger. There is no built-in mechanism.

Why are the Liminal records showing the toflourish__ prefix? Liminal is a namespaced managed package — all custom objects and fields carry the toflourish__ prefix when installed in a subscriber org. This is normal Salesforce managed-package behavior; the prefix does not appear on field labels, only in API names.


Quick setup checklist

  • Custom metadata record FL_Liminal__mdt with name global created and populated (Braintree Token, Sandbox Mode, Completed Order StageName, support email).
  • Permission set Liminal Admin assigned to all admin users.
  • Remote Site Settings FL_Braintree and FL_BraintreeSandbox active.
  • Campaign (engagement) created, marked Active, with Start/End dates and Event Image URL.
  • Liminal Offering records created, linked via Engagement, with Label, Description, Image, and Price set.
  • Liminal Availability records created with the correct record type (Stock / Slot / Hybrid) and capacity values.
  • Lightning page built with Liminal: Ticket Storefront and/or Liminal: Calendar plus Liminal: Checkout, all sharing one orderId.
  • Guest user permissions and sharing rules in place if publishing publicly.
  • Confirmation email Flow built (record-triggered on Opportunity).
  • End-to-end smoke test in incognito with a Braintree sandbox card.
  • Production cutover: flip Braintree Sandbox Mode off in FL_Liminal__mdt.

Troubleshooting

SymptomFirst place to look
Storefront page is emptyCampaign is not Active, or guest user cannot see it, or the Engagement Id on the component is wrong.
Calendar shows no slotsNo Open-type Availabilities, or they are outside the Campaign's date range, or every day is blocked by a Close window, or Weekend_Availability = Unavailable is hiding the only days you scheduled.
Checkout says "No org-wide settings have been configured"The global FL_Liminal__mdt record is missing or named differently.
Checkout charges but no Opportunity appearsLook for the customer-recovery message — there was a Salesforce DML failure after the charge. Search Opportunities by Lim Order ID = <orderId> and create one manually if needed.
Inventory doesn't decrementThe Selection's Price__c is null (volunteer-style records don't count toward Quantity_* rollups). They still count toward Slots_* rollups.
Duplicate Contact createdThe fuzzy match needs both a name component and an email or phone exact match. Records with only addresses can slip through; tighten data hygiene or pre-create the Contact.
Inventory math looks staleSave any minor edit on the Offering or Availability to retrigger the rollup.
Recurring donation didn't get createdCheck that NPSP is installed (npe03 namespace) and the running user has access to npe03__Recurring_Donation__c.
Payment form won't load on Experience siteOpen browser dev console — usually CSP blocking the Braintree script. Add *.braintreegateway.com and *.braintree-api.com to CSP Trusted Sites if needed.