Skip to Content

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

SettingRequiredInputDescription
Publishable keyYesTextYour Stripe publishable key, which is safe to expose to the client
Secret keyYesSecretYour Stripe secret key, used on the server
Endpoint secretYesGenerate and bindThe 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 typeDefaultRecommendation
One-time paymentGranted to all rolesKeep it for roles that need to pay, such as logged-in users
SubscriptionGranted to all rolesKeep it for roles that need to subscribe; it covers starting and canceling recurring payments
RefundNot grantedGrant 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_value equals payment_record/order/{amount field}.
  • payment_record/currency equals payment_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:

  1. Add a Database node that updates the order table and sets the order status to paid.
  2. 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/status equals REFUNDED: The refund succeeded. Inside this branch, add another Condition node to tell a full refund from a partial one:
    • refund/amount equals refund/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/status equals FAILED: 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_DUE or UNPAID: A charge did not succeed. Suspend access or remind the user as your business requires.
  • Status is CANCELED or INCOMPLETE_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 id equals recurring_payment/account_id.
  • To update the order, filter the order table where id equals recurring_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_record table where id equals payment_id.
  • Add a Database node that queries the order table where id equals payment_record/recurring_payment/first_order_id to 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.

ParameterTypeRequiredDescription
Order idIntegerYesID of the order record in the bound order table
CurrencyTextYesA currency code supported by Stripe, such as USD
AmountDecimalYesAmount in the smallest currency unit; for example, enter 1000 to charge USD 10.00
Product nameTextNoProduct name shown at checkout
Product descriptionTextNoProduct 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.

ParameterTypeRequiredDescription
Payment idIntegerYesID of the payment record to refund, not the order ID
Refund AmountDecimalYesAmount 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.

ParameterTypeRequiredDescription
Order idIntegerYesID of the order record for the first subscription period
Price idTextYesID of the Stripe recurring price
Product nameTextNoProduct name shown at checkout
Product descriptionTextNoProduct 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

  1. Generate and bind is unavailable: Bind the Secret key before you generate the endpoint secret.
  2. 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.
  3. 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.
  4. 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.
  5. The subscription is authorized but access is not granted: Rely on the ACTIVE status of the recurring_payment record, not only on the frontend success branch.
  6. A renewal creates a payment record without an order: Make sure the On recurring billing Actionflow uses synchronous execution and returns the order ID.
Last updated on