Setup
How to get Flourish Payments ready in an org after installing it, before a payment form can take money.
Overview
There are five pieces:
- The permission set, for the people who work with payments.
- The Flourish Payments Setting record, which holds your Stripe keys.
- An Experience Cloud site that hosts the public connector.
- A webhook in Stripe.
- The components on your Opportunity and Product record pages.
Your website's payment form won't reach Salesforce until the first three are in place, and payments won't reconcile onto records until the webhook is.
You need a Stripe account and access to its dashboard, because three values come from there: the publishable key, the secret key, and the webhook signing secret.
Flourish Payments has no tabs and no app of its own. Everything it does happens on the Opportunity and Product record pages, in Flow, or on your own website.
Permission set
One permission set ships with the package.
| Permission set | Give it to |
|---|---|
| Flourish Payments: Admin | People who read or edit payment details on records, and people who send products to Stripe. |
It grants read and edit on these fields:
- Opportunity: Stripe Sync, Payment Custom Data, External Ids, Payment Model, Initial Stripe Checkout Datetime and Subscription Opportunity.
- Contact: Stripe Customer ID.
- Product: Stripe Sync.
It also grants the access the Flourish Payments: Stripe Product component needs. The guest user of your connector site is a separate grant, covered below.
Flourish Payments Setting
All org-wide configuration lives in one custom metadata record.
Go to Setup > Custom Metadata Types > Flourish Payments Setting > Manage Records. The record is named global, in lower case. If it's not there, click New and set both the label and the record name to global.
| Field | What it holds |
|---|---|
| Stripe Public Key | Your Stripe publishable key, pk_live_... or pk_test_.... This one is sent to the browser. |
| Stripe Secret Key | Your Stripe secret key, sk_live_... or sk_test_.... It stays in Salesforce and is never sent to the browser. |
| Stripe Webhook Secret | The signing secret Stripe gives you when you create the webhook, whsec_.... Every inbound event is checked against it. |
| Opportunity Record Type | Developer name of the record type for Opportunities the package creates. Leave blank for the org default. |
| Default Opportunity Stage | Stage for those Opportunities. Leave blank and the package picks the first open stage. |
| Pricing Flow Name | API name of an Autolaunched Flow that computes the charge amount. Leave blank unless you need it. See Server-side pricing. |
| Public Connector URL | Optional, for your own reference. The payment form takes the connector's address from its own configuration, so nothing reads this field. |
| Stripe Account ID | Leave blank. Nothing reads it. |
The package includes the Remote Site Setting for Stripe, so callouts work with no extra configuration.
Keep the secret key and the webhook secret to the people who need them. Anyone who can open this record can read both.
The public connector site
Your payment form runs on your own website, which can't call Salesforce directly. It reaches Salesforce through Flourish Payments: Public Connector, a component you host on an Experience Cloud page. The form loads that page in a frame and talks to it. The secret key stays in Salesforce; only the publishable key reaches the browser.
- Create an Experience Cloud site, or use one you already have. A bare LWR site is enough, since nothing on the page is meant to be seen.
- Add the Flourish Payments: Public Connector component to a page on that site.
- Open the site to guests. In Experience Builder, under Settings > General, turn on public access.
- Give the site's guest user two Apex classes,
pay_StripePublicUtilityfor the connector andpay_StripeWebhookfor the webhook. Grant them on the guest profile, or on a permission set assigned to the guest user. Nothing else is needed: the connector runs in system mode, with no object or field permissions of its own. - Let your website frame the site. List every host your payment form runs on, with and without
www, in three places:- In Experience Builder, under Settings > Security & Privacy, set Clickjack Protection Level to Allow framing of site pages on external domains.
- On the same page, add each host under Trusted Domains for Inline Frames.
- In Setup, under CSP Trusted Sites, add each host.
- Publish the site. Changes don't reach the served pages until you do.
The connector page's URL is what the page author sets as paymentsLwc.siteUrl in the form's configuration. See Payment widget.
The Stripe webhook
Stripe tells Salesforce what happened after the customer pays. Without the webhook, Opportunities created by a checkout stay at their opening stage even when the payment went through, and invoices and subscriptions never update.
1. Build the endpoint URL
The webhook runs through the same Experience Cloud site, at its vforcesite address, with the package's toflourish namespace in the path:
https://YOUR-DOMAIN.my.site.com/SITE-PREFIXvforcesite/services/apexrest/toflourish/payments/webhook
For a site whose URL prefix is payments, that's https://YOUR-DOMAIN.my.site.com/paymentsvforcesite/services/apexrest/toflourish/payments/webhook. Without toflourish in the path, the site answers 404.
2. Add the endpoint in Stripe
In the Stripe dashboard, go to Developers > Webhooks and click Add endpoint:
- Paste the URL.
- Choose an API version of
2025-03-31or later. - Subscribe to these twelve events:
| Event | Needed for |
|---|---|
checkout.session.completed | Every payment form and payment link |
checkout.session.async_payment_succeeded | Bank payments that clear later |
checkout.session.async_payment_failed | Bank payments that fail |
checkout.session.expired | Checkouts the customer abandoned |
charge.refunded | Refunds |
invoice.paid | Invoices and subscription renewals |
invoice.payment_failed | Invoices and subscription renewals |
invoice.voided | Invoices |
invoice.marked_uncollectible | Invoices |
customer.subscription.created | Subscriptions |
customer.subscription.updated | Subscriptions |
customer.subscription.deleted | Subscriptions |
What each one does to a record is on Payments in Salesforce.
A Stripe account you also use for other things is fine. Events for payments Salesforce didn't start are acknowledged and ignored. A refund Salesforce can't match is retried for up to a day first, in case its payment is still being recorded.
3. Save the signing secret
Copy the signing secret Stripe shows for the endpoint and paste it into Stripe Webhook Secret on the global record.
Record pages
Add these in the Lightning App Builder:
| Component | Page | What it's for |
|---|---|---|
| Flourish Payments: Stripe Sync Viewer | Opportunity | The payments, invoices and subscription on the record. See Payments in Salesforce. |
| Flourish Payments: Custom Data Viewer | Opportunity | What the form collected beyond the standard payment fields. |
| Flourish Payments: Stripe Product | Product | Sending a product to Stripe, with its prices and payment links. See Products, invoices and subscriptions. |
Checking it works
- Open the connector page in a browser. It renders nothing, which is correct. What matters is the browser console: it logs
FL Payments connected. If it warns about loading connector init instead, the guest user is missing thepay_StripePublicUtilityclass. - Run a test payment with Stripe in test mode and a test card. The form should reach the Stripe payment step. If it stalls before that with a timeout message, check the connector URL, the guest grant and the three framing settings.
- Open the Opportunity the checkout created and confirm the payment shows as Completed in the Stripe Sync Viewer. Still Pending a minute after paying means the webhook isn't arriving: check its delivery attempts in the Stripe dashboard.
- Read the webhook's responses in Stripe.
- A 404 means the URL is missing
toflourishorvforcesite. - A 401 with "Invalid signature" means Stripe Webhook Secret doesn't match the endpoint.
- A 404 means the URL is missing