Stripe Payment
Momen uses the Stripe Payment Element to support one-time payments in multiple currencies, recurring payments, and refunds. Before you begin, read the Payment Overview to prepare an order table and learn how payment results are handled.
Before you begin
- Sign up for or sign in to Stripe .
- In the Stripe Dashboard, open Developers → API keys, copy the publishable key, and reveal the secret key. Do not mix test keys with live keys.
- If you need recurring payments, create a product and a recurring price in the Stripe Dashboard and copy the price ID. See How to create products and prices .
Set up the payment configuration
Create a payment configuration
Open Action → Payment, select Create new, enter a name for the configuration, choose Stripe as the Payment channel, and select Create and start configuration. If this is the project’s first payment configuration, you need to bind an order table first.
Enter merchant information
| Setting | Required | Input | Description |
|---|---|---|---|
| Publishable key | Yes | Text | Your Stripe publishable key, which is safe to expose to the client |
| Secret key | Yes | Secret | Your Stripe secret key, used on the server |
| Endpoint secret | Yes | Generate and bind | The Stripe webhook signing secret, generated by Momen |
Bind the Secret key first, then select Generate and bind next to Endpoint secret. Momen uses the secret key to create a Stripe webhook that points to this configuration’s Notification URL, and saves the signing secret as a secret.
If you change the secret key or the notification URL, select Regenerate and bind. Momen deletes the existing Stripe webhook for the same URL and creates a new one.
Do not change the events or the URL of the webhook that Momen creates in Stripe. To handle other Stripe events, create a separate Actionflow with a Webhook Trigger, and create a dedicated webhook for it in Stripe.
Choose payment products and clients
Under Payment products, select Element. Under Client management, select your web app client.
Set up payment result handling
Under Payment result handling, bind an Actionflow to each of On payment, On refund, On subscription status change, and On recurring billing. For details, see Set up payment result Actionflows below.
Set permissions
Open Permission management and select the payment types each role can start through this configuration:
| Payment type | Default | Recommendation |
|---|---|---|
| One-time payment | Granted to all roles | Keep it for roles that need to pay, such as logged-in users |
| Subscription | Granted to all roles | Keep it for roles that need to subscribe; it covers starting and canceling recurring payments |
| Refund | Not granted | Grant it only to trusted administrator roles |
You can also review and change these permissions under Settings → Permissions → Payment.
Set up payment result Actionflows
Stripe has four payment events: On payment, On refund, On subscription status change, and On recurring billing. If you only use one-time payments, you only need the first two. When Momen receives a notification from Stripe, it updates the corresponding payment records first and then runs the matching Actionflow. Use these Actionflows to update orders, grant or revoke access, and handle any other business logic.
On payment
When a user’s payment succeeds, the payment record changes to SUCCESSFUL and Momen runs this Actionflow. It does not run when a payment fails or the user cancels it.
Add an input
Add an input named payment_id (Integer) to the Actionflow, and in the payment configuration, bind it to Payment callback → Payment → id.
Query the payment record
Add a Database node that queries the payment_record table where id equals payment_id.
Verify the payment amount
The amount actually paid may differ from the amount on the order, so verify the amount before you do anything else.
Do not skip this step. Without it, an attacker can tamper with the payment amount and complete an order for far less than its price, causing you a direct financial loss.
Add a Condition node that checks both of the following:
payment_record/grand_total_valueequalspayment_record/order/{amount field}.payment_record/currencyequalspayment_record/order/{currency field}.
Stripe stores grand_total_value in the smallest currency unit; for example, USD 10.00 is stored as 1000. If your order amount uses a different unit, convert it before comparing.
Update the order and grant access
In the branch where the condition is met:
- Add a Database node that updates the order table and sets the order status to paid.
- Grant access as your business requires, for example by activating a membership for the account, adding points, or sending a notification.
The finished Actionflow looks like this:
On refund
Once a refund has a result, the refund record changes to REFUNDED (the refund succeeded) or FAILED (the refund failed), and Momen runs this Actionflow. Because it runs in both cases, handle each one separately.
Add an input
Add an input named refund_id (Integer), and in the input configuration, bind it to Payment callback → Refund → id.
Query the refund record
Add a Database node that queries the refund table where id equals refund_id.
Handle each refund result
Add a Condition node with the following branches:
refund/statusequalsREFUNDED: The refund succeeded. Inside this branch, add another Condition node to tell a full refund from a partial one:refund/amountequalsrefund/payment_record/grand_total_value: It is a full refund. Update the order status and revoke all access that was granted.- Otherwise: It is a partial refund. Update the order status as your business requires and revoke the corresponding part of the access.
refund/statusequalsFAILED: The refund failed. Notify an administrator or the user as needed, and leave the order unchanged.
The finished Actionflow looks like this:
On subscription status change
When the status of a subscription or its cancel at period end flag changes, Momen updates the recurring_payment record and runs this Actionflow, for example when a subscription becomes active, a charge becomes overdue, or a subscription is canceled. Notifications that only move the billing period do not run it.
Add an input
Add an input named recurring_payment_id (Integer), and in the input configuration, bind it to Payment callback → Recurring payment → id. If you need to know which status the subscription changed from, add a Text input as well and bind it to Payment callback → Previous status.
Query the recurring payment record
Add a Database node that queries the recurring_payment table where id equals recurring_payment_id.
Handle each subscription status
Add a Condition node with the following branches:
- Status is
ACTIVE: Activate or restore the subscriber’s access. - Status is
PAST_DUEorUNPAID: A charge did not succeed. Suspend access or remind the user as your business requires. - Status is
CANCELEDorINCOMPLETE_EXPIRED: The subscription has ended. Revoke the subscriber’s access.
When a branch adds a Database node to update data, you can filter by fields of the recurring payment record:
- To update the account, filter the account table where
idequalsrecurring_payment/account_id. - To update the order, filter the order table where
idequalsrecurring_payment/first_order_id.
When a user cancels a subscription, cancel at period end changes to true first. The subscription remains valid until the end of the current period, so you can remind the user if needed. The status changes to CANCELED only when the period ends.
The finished Actionflow looks like this:
On recurring billing
When a subscription issues a new invoice, Momen creates a payment record for that billing period and runs this Actionflow. The payment record is not yet linked to an order, and the only job of this Actionflow is to create that order and return its ID.
This Actionflow must use synchronous execution and output the ID of the new order. Otherwise, the editor reports an error and the payment record for that period cannot be linked to an order.
Set the execution mode and output
Set the Actionflow to synchronous execution, and add an Integer output that returns the ID of the new order.
Add an input
Add an input named payment_id (Integer), and in the input configuration, bind it to Payment callback → Payment → id.
Query the payment and order records
- Add a Database node that queries the
payment_recordtable whereidequalspayment_id. - Add a Database node that queries the order table where
idequalspayment_record/recurring_payment/first_order_idto get the first order of the subscription.
Create the order for this billing period
Add a Database node that inserts a new order into the order table. Fill in the amount, account, product, and other fields from the order record you queried in the previous step, and set the order status to pending payment.
Return the order ID
Assign the ID of the new order to the output. Momen writes it back to the payment record for this period.
The finished Actionflow looks like this:
Only create the order here; do not grant access. When the charge for this period succeeds, On payment runs, and that is where you update the order and grant access for the period after the amount check.
Set up frontend payment actions
One-time payments
Add an action that creates the order
Before calling the payment action, create an order in the bound order table. Keep the order amount, products, user, and other business data in the order table.
Add the payment action
Add a Payment action to the Trigger of a button or another component. Set Payment type to One-Off Payment, select the Stripe configuration you created under Payment configuration, and select Element as the Payment product.
| Parameter | Type | Required | Description |
|---|---|---|---|
| Order id | Integer | Yes | ID of the order record in the bound order table |
| Currency | Text | Yes | A currency code supported by Stripe, such as USD |
| Amount | Decimal | Yes | Amount in the smallest currency unit; for example, enter 1000 to charge USD 10.00 |
| Product name | Text | No | Product name shown at checkout |
| Product description | Text | No | Product description shown at checkout |
Each currency has a minimum charge amount. See the Stripe documentation .
The On success branch of the payment action means only that the frontend call returned successfully; On payment determines the final payment status. For security reasons, actions that modify data cannot be added under On success.
Handle the completed payment
When the payment succeeds, Momen changes the payment record to SUCCESSFUL and runs the Actionflow bound to On payment, where you update the order and grant access. See On payment.
Show the final result
Query the order table or the payment_record table on the frontend to show the final status. To refresh the status promptly, use a subscription query.
Refunds
Grant the refund permission
Refunds are not granted by default. Under Permission management in the payment configuration, select Refund only for trusted administrator roles.
Add the refund action
Add a Payment action and set Payment type to Refund.
| Parameter | Type | Required | Description |
|---|---|---|---|
| Payment id | Integer | Yes | ID of the payment record to refund, not the order ID |
| Refund Amount | Decimal | Yes | Amount in the smallest unit of the original currency; if it exceeds the remaining refundable amount, only the remaining amount is refunded |
To get the payment ID, query the payment_record table filtered by the order ID. Only payment records in SUCCESSFUL or PARTIALLY_REFUNDED status can be refunded.
Handle the refund result
A new refund record starts in REFUNDING status. When Stripe reports the result, Momen changes the refund record to REFUNDED or FAILED and runs the Actionflow bound to On refund. If Stripe rejects the refund request outright, the refund record changes to FAILED and the refund action enters On failure. See On refund.
Recurring payments
Start a subscription
Add a Payment action. Set Payment type to Recurring Payment and Type to Initiate, select the Stripe configuration you created under Payment configuration, and select Element as the Payment product.
| Parameter | Type | Required | Description |
|---|---|---|---|
| Order id | Integer | Yes | ID of the order record for the first subscription period |
| Price id | Text | Yes | ID of the Stripe recurring price |
| Product name | Text | No | Product name shown at checkout |
| Product description | Text | No | Product description shown at checkout |
Momen then creates a recurring_payment record in INCOMPLETE status and a payment record linked to the first order. On payment runs when the first charge succeeds, and On subscription status change runs when the subscription becomes active. The frontend branches reflect only the checkout interaction; whether the subscription is active is determined by the status of the recurring_payment record.
Cancel a subscription
Add a Payment action. Set Payment type to Recurring Payment and Type to Cancel, and bind the Recurring Payment id of the subscription to cancel.
The subscription ends at the end of the current period. Its cancel at period end flag changes to true immediately, and its status changes to CANCELED when the period ends, which runs On subscription status change.
Troubleshooting
- Generate and bind is unavailable: Bind the Secret key before you generate the endpoint secret.
- Checkout does not open: Make sure the publishable key and the secret key come from the same Stripe environment, and that all required inputs of the payment action are bound.
- The payment status does not update: Make sure the endpoint secret was generated with the current secret key and that the payment configuration has been published.
- The amount charged is not what you expected: Stripe amounts use the smallest currency unit. Check how many decimal places the currency has before you bind the amount.
- The subscription is authorized but access is not granted: Rely on the
ACTIVEstatus of therecurring_paymentrecord, not only on the frontend success branch. - A renewal creates a payment record without an order: Make sure the On recurring billing Actionflow uses synchronous execution and returns the order ID.