Skip to main content

Flow actions

Four actions Flourish Payments adds to Flow: two that charge a card the customer already saved, and two that read the data a payment form collected.

In Flow Builder, add an Action element and look under the Flourish Payments category.

Charging a saved card

When a customer ticks the box to save their card at checkout, the package keeps a token for it. The token is not the card: it is a reference Stripe accepts on your behalf, for that customer, with no one at the keyboard. That is what both charging actions spend.

The token is stored with the rest of the payment history in Stripe Sync on the Opportunity, in this shape:

{
"stripeCustomerId": "cus_...",
"paymentMethodToken": "pm_...",
"paymentMethodStatus": "active"
}

Charge Payment Token

The action to use for anything recurring. It reads the credential out of a field rather than taking it as an input, which means the token can live in one place and every record that needs it can point at that place.

InputRequiredWhat it takes
Credential JSON FieldYesThe field holding the JSON above. A path through a parent works, so npe03__Recurring_Donation__r.Stripe_Credentials__c reads the token off the parent rather than needing a copy on every child.
Amount FieldYesThe field holding the dollar amount to charge, for example Amount.
Record IDOne of these twoCharge this one record now, and wait for the answer.
SOQL QueryOne of these twoCharge every row this query returns, in the background.
CurrencyNoISO currency code. Defaults to usd.
DescriptionNoA description sent to Stripe with the charge.
Chunk SizeNoHow many charges run per transaction on the background path. Defaults to 50, capped at 90.
OutputWhat it tells you
SuccessThe single charge went through. Only meaningful on the Record ID path.
Payment Intent ID, Status, Error MessageThe result of that single charge.
EnqueuedThe background run started.
Records QueuedHow many rows it will charge.
Records SkippedHow many rows it refused to charge, and why is on each record's result.

Two paths, and they behave differently. Give it a Record ID and the charge happens while the Flow waits, so a Screen Flow can tell the person at the desk what happened. Give it a SOQL Query and it hands the work off and returns straight away: a scheduled Flow that charges a month of installments gets Enqueued and a count, not an outcome per row. Check the records themselves for those.

Pass one query rather than looping records and calling the action per row. The query is what keeps a large run inside Salesforce's limits, and the action charges in chunks, each chunk its own transaction.

Rows it will not charge. A row whose credential field is empty, whose JSON has no token or no customer, or whose paymentMethodStatus is anything but active, is skipped before any money moves and counted in Records Skipped. Put the same conditions in your query's WHERE clause anyway; the guard is there for the rows that slip through.

Charging twice is guarded against. Each charge carries a key built from the record and the date, and Stripe honors it: if a background run dies partway and is retried the same day, the rows it already charged return their original result instead of charging again.

A successful charge writes a receipt and stops there. It appends the payment to Stripe Sync and nothing else. It does not set the stage to Closed Won and does not mark a payment record paid, because what a recurring charge means for your records is yours to decide. Do it in the same Flow, after the action.

The query is checked before it runs. It has to be a single SELECT with no semicolon, and it must select the credential field and the amount field you named.

Charge Saved Payment Method

The same charge, with the credentials handed to it directly. Use it when the Flow already has the customer and token in variables, or when the token does not live in a field on the record.

InputRequiredWhat it takes
Stripe Customer IDYesThe cus_... customer.
Payment Method IDYesThe pm_... token saved at a previous checkout.
AmountYesDollars, for example 25.00.
OutputWhat it tells you
SuccessWhether the charge went through.
Payment Intent IDStripe's ID for the charge.
StatusWhat Stripe reported.
Error MessageThe decline reason or the error, when Success is false.

This one charges and returns. It writes nothing to the Opportunity, so anything you want recorded, record it in the Flow.

Reading what the form collected

Both of these read Payment Custom Data, where every form field the package does not handle itself ends up. See Payments in Salesforce.

Get Custom Data Value

Pulls one value out by name.

InputRequiredWhat it takes
Key NameYesThe field name from the form. Dot notation reaches nested values, for example pricing.source.
Opportunity IDIf no JSON StringThe Opportunity to read.
JSON StringIf no Opportunity IDThe JSON itself. In a record-triggered Flow, pass $Record.pay_Custom_Data__c and save the query.

The output is Value.

Filter by Custom Data

Narrows a list of Opportunities to the ones whose custom data matches.

InputRequiredWhat it takes
Opportunity IDsYesComma-delimited list to test.
Key NameYesThe field name, dot notation allowed.
OperatorNoequals (the default), not_equals, contains, not_contains, is_blank, is_not_blank.
Key ValueNoWhat to compare against. Not needed for is_blank and is_not_blank.

The output is Matching IDs, comma-delimited. Comparisons are case-sensitive.