Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Developer tools
Get started
Payments
Finance automation
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
Payment methods
Add payment methods
    Overview
    Payment method integration options
    Manage default payment methods in the Dashboard
    Payment method types
    Cards
    Pay with Stripe balance
    Bank debits
    Bank redirects
      Bancontact
      BLIK
      EPS
      FPX
        Accept a payment
      iDEAL
      Przelewy24
      SOFORT
      TWINT
    Bank transfers
    Credit transfers (Sources)
    Buy now, pay later
    Real-time payments
    Vouchers
    Wallets
    Enable local payment methods by country
    Custom payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
Other Stripe products
Financial Connections
Crypto
Climate
HomePaymentsAdd payment methodsBank redirectsFPX

Accept an FPX payment

Learn how to accept FPX, a common payment method in Malaysia.

Copy page

Caution

The content of this section refers to a Legacy product. You should use the Accept a payment guide for the most recent integration path instead. While Stripe still supports this product, this support might end if the product is deprecated.

FPX is a single-use payment method. Customers pay with FPX by redirecting from your website, sending you payment, then returning to your website where you get immediate notification on whether the payment succeeded or failed.

To enable FPX payments:

  1. Navigate to the Payment methods settings in the Dashboard. If you haven’t already, activate your Stripe account.
  2. Find FPX under Bank redirects and select Turn on.
  3. Accept the FPX terms of service.

FPX is only available to merchants based in Malaysia. See payment method support for more information about countries, currencies, and payment methods compatible with Stripe products.

Note

FPX is a single-use payment method and can’t be used for recurring or additional payments. It’s currently not supported with Stripe Billing. Support for FPX payments for Custom accounts is in beta. Please reach out to Stripe support for any support queries.

Set up Stripe
Server-side

First, you need a Stripe account. Register now.

Use our official libraries for access to the Stripe API from your application:

Command Line
Ruby
# Available as a gem sudo gem install stripe
Gemfile
Ruby
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Create a PaymentIntent
Server-side

A PaymentIntent represents your intent to collect payment from a customer, tracking the lifecycle of the payment process through each stage. Create a PaymentIntent as soon as you know the amount (for example, the beginning of the checkout process). You need the following values to create the PaymentIntent:

ParameterValue
payment_method_typesfpx
amountA positive integer in the smallest currency unit that represents the amount to charge the customer (for example, 1099 for a RM10.99 payment). Stripe supports a minimum amount of RM2 and a maximum amount of RM30,000 per transaction.
currencymyr (FPX must always use Ringgit).
Command Line
cURL
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d "payment_method_types[]"=fpx \ -d amount=1099 \ -d currency=myr

You can also update the amount if it changes later (for example, when calculating shipping fees and taxes):

Command Line
cURL
curl https://api.stripe.com/v1/payment_intents/pi_1DRuHnHgsMRlo4MtwuIAUe6u \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1499

Collect payment method details
Client-side

Stripe Elements is a set of prebuilt UI components for collecting payment details. Elements is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.

checkout.html
<head> <title>Checkout</title> <script src="https://js.stripe.com/v3/"></script> </head>

Create an instance of Elements with the following JavaScript on your checkout page.

const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); const elements = stripe.elements();

Elements needs a place to live in your payment form. Create empty DOM nodes (containers) with unique IDs in your payment form and then pass those IDs to Elements.

checkout.html
<form id="payment-form"> <div class="form-row"> <div> <label for="fpx-bank-element"> FPX Bank </label> <div id="fpx-bank-element"> <!-- A Stripe Element will be inserted here. --> </div> </div> </div> <button id="fpx-button" data-secret="{{ CLIENT_SECRET }}"> Submit Payment </button> <!-- Used to display form errors. --> <div id="error-message" role="alert"></div> </form>

When the form above has loaded, create an instance of an fpxBank Element and mount it to the Element container created above.

const style = { base: { // Add your base input styles here. For example: padding: '10px 12px', color: '#32325d', fontSize: '16px', }, }; // Create an instance of the fpxBank Element. const fpxBank = elements.create( 'fpxBank', { style: style, accountHolderType: 'individual', } ); // Add an instance of the fpxBank Element into the container with id `fpx-bank-element`. fpxBank.mount('#fpx-bank-element');

Submit the payment to Stripe
Client-side

To create a payment on the client side, pass the client secret of the PaymentIntent object that you created in Step 1.

Use stripe.confirmFpxPayment to handle the redirect away from your page and to complete the payment. Add a return_url to this function to indicate where Stripe should redirect the user after they complete the payment on their bank’s website or mobile application.

client.js
const form = document.getElementById('payment-form'); form.addEventListener('submit', async function(event) { event.preventDefault(); const fpxButton = document.getElementById('fpx-button'); const clientSecret = fpxButton.dataset.secret; const result = await stripe.confirmFpxPayment(clientSecret, { payment_method: { fpx: fpxBank, }, // Return URL where the customer should be redirected after the authorization return_url: `${window.location.href}`, }); if (result.error) { // Inform the customer that there was an error. const errorElement = document.getElementById('error-message'); errorElement.textContent = result.error.message; } });

When your customer submits a payment, Stripe redirects them to the return_url and includes the following URL query parameters. The return page can use them to get the status of the PaymentIntent so it can display the payment status to the customer.

When you specify the return_url, you can also append your own query parameters for use on the return page.

ParameterDescription
payment_intentThe unique identifier for the PaymentIntent.
payment_intent_client_secretThe client secret of the PaymentIntent object. For subscription integrations, this client_secret is also exposed on the Invoice object through confirmation_secret

When the customer is redirected back to your site, you can use the payment_intent_client_secret to query for the PaymentIntent and display the transaction status to your customer.

Test your integration

Authentication success and failure cases

Test your FPX integration by selecting any bank with your test API keys and viewing the redirect page. You can test the successful payment case by authenticating the payment on the redirect page. The PaymentIntent will transition from requires_action to succeeded.

To test the case where the user fails to authenticate, select any bank with your test API keys. On the redirect page, click Fail test payment. The PaymentIntent will transition from requires_action to requires_payment_method.

Confirmation error cases

Other error cases you might encounter are connecting to banks that are offline and processing errors during confirmation. To trigger these errors, set the fpx[bank] value on confirm to one of the test error bank values below. The PaymentIntent state will be requires_confirmation. Learn more about these error codes.

ParameterValueError code
fpx[bank]test_offline_bankoffline_bank
fpx[bank]test_processing_errorpayment_method_processing_error_transient

Handle post-payment events
Server-side

Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events also helps you accept more payment methods in the future. Learn about the differences between all supported payment methods.

Manually

Use the Stripe Dashboard to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments.

  • View your test payments in the Dashboard

Custom code

Build a webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

  • Build a custom webhook

Prebuilt apps

Handle common business events, like automation or marketing and sales, by integrating a partner application.

OptionalHandle FPX bank element events

OptionalHandle FPX redirect manually

Checkout and payment confirmation requirements

You must adhere to the following requirements on your checkout page:

RequirementDetail
Display the FPX logo.Download the FPX logo here.
Create FPX Buyer Bank’s selection in a dropdown list.Bank names must match the names in the bank reference.
Present the FPX Terms & Conditions standard wording and URL.Standard wording: By clicking on the Proceed button, you agree to FPX’s Terms and Conditions.

The following information must be displayed on the payment confirmation page that your customer returns to after completing their bank authentication.

InformationSource of information
Transaction Date & Timecreated from the Charge object.
Amountamount from the Charge object.
Seller Order No.statement_descriptor from the Charge object.
FPX Transaction IDpayment_method_details[fpx][transaction_id] from the Charge object.
Buyer Bank Namepayment_method_details[fpx][bank] from the Charge object
Transaction Statusstatus from the Charge object

You can access this information on the Charge by retrieving it from the payment_intent.succeeded event.

Users on API version 2022-08-01 or older: You can access this information on the Charge by retrieving it from the payment_intent.succeeded event or directly from the PaymentIntent.

Ruby
# Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
intent = Stripe::PaymentIntent.retrieve('{{PAYMENT_INTENT_ID}}') charges = intent.charges.data

Bank reference

Bank nameValue
Affin Bankaffin_bank
Alliance Bankalliance_bank
AmBankambank
Bank Islambank_islam
Bank Muamalatbank_muamalat
Bank Rakyatbank_rakyat
BSNbsn
CIMB Clickscimb
Hong Leong Bankhong_leong_bank
HSBC Bankhsbc
KFHkfh
Maybank2Emaybank2e
Maybank2Umaybank2u
OCBC Bankocbc
Public Bankpublic_bank
RHB Bankrhb
Standard Charteredstandard_chartered
UOB Bankuob

Error codes

These are the common error codes and corresponding recommended actions:

Error CodeRecommended Action
invalid_amountFPX transactions must be greater than RM2 and less than RM30,000.
invalid_bankThe provided bank is not supported by FPX. Please use one of the options from the Bank Reference above.
invalid_currencyFPX only supports MYR transactions.
missing_parameterA required parameter is missing. Please check the error_message for more information about which parameter is required.
offline_bankThe provided bank is currently offline. Please try using a different bank or payment method type.
payment_method_not_availableThe payment method is currently not available. You should invite your customer to fallback to another payment method to proceed.
payment_method_processing_error_transientAn unexpected error occurred preventing us from confirming the payment intent. The payment intent confirmation should be retried.

Payouts and transfers

For compliance reasons, your FPX funds settle in a separate fpx balance on your account. This means that you may receive two separate automatic payouts in a single day, one for your FPX funds and another for all other funds. For Connect platforms, you can create a payout or transfer from your fpx balance by specifying fpx as the source_type:

Command Line
cURL
curl https://api.stripe.com/v1/payouts \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=5000 \ -d currency=myr \ -d source_type=fpx

You can also retrieve your balance to see a breakdown of your available and pending Stripe balances by source_type.

Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc