Accept an FPX payment
Learn how to accept FPX, a common payment method in Malaysia.
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:
- Navigate to the Payment methods settings in the Dashboard. If you haven’t already, activate your Stripe account.
- Find FPX under Bank redirects and select Turn on.
- 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 StripeServer-side
First, you need a Stripe account. Register now.
Use our official libraries for access to the Stripe API from your application:
Create a PaymentIntentServer-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:
Parameter | Value |
---|---|
payment_ | fpx |
amount | A 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. |
currency | myr (FPX must always use Ringgit). |
You can also update the amount if it changes later (for example, when calculating shipping fees and taxes):
Collect payment method detailsClient-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.
<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(
); const elements = stripe.elements();'pk_test_TYooMQauvdEDq54NiTphI7jx'
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.
<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 StripeClient-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_
to this function to indicate where Stripe should redirect the user after they complete the payment on their bank’s website or mobile application.
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_
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_
, you can also append your own query parameters for use on the return page.
Parameter | Description |
---|---|
payment_ | The unique identifier for the PaymentIntent . |
payment_ | The client secret of the PaymentIntent object. For subscription integrations, this client_secret is also exposed on the Invoice object through confirmation_ |
When the customer is redirected back to your site, you can use the payment_
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_
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_
to requires_
.
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_
. Learn more about these error codes.
Parameter | Value | Error code |
---|---|---|
fpx[bank] | test_ | offline_ |
fpx[bank] | test_ | payment_ |
Handle post-payment eventsServer-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.
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.
Prebuilt apps
Handle common business events, like automation or marketing and sales, by integrating a partner application.
Checkout and payment confirmation requirements 
You must adhere to the following requirements on your checkout page:
Requirement | Detail |
---|---|
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.
Information | Source of information |
---|---|
Transaction Date & Time | created from the Charge object. |
Amount | amount from the Charge object. |
Seller Order No. | statement_ from the Charge object. |
FPX Transaction ID | payment_ from the Charge object. |
Buyer Bank Name | payment_ from the Charge object |
Transaction Status | status from the Charge object |
You can access this information on the Charge by retrieving it from the payment_
event.
Users on API version 2022-08-01 or older: You can access this information on the Charge by retrieving it from the payment_
event or directly from the PaymentIntent.
Bank reference 
Bank name | Value |
---|---|
Affin Bank | affin_bank |
Alliance Bank | alliance_bank |
AmBank | ambank |
Bank Islam | bank_islam |
Bank Muamalat | bank_muamalat |
Bank Rakyat | bank_rakyat |
BSN | bsn |
CIMB Clicks | cimb |
Hong Leong Bank | hong_leong_bank |
HSBC Bank | hsbc |
KFH | kfh |
Maybank2E | maybank2e |
Maybank2U | maybank2u |
OCBC Bank | ocbc |
Public Bank | public_bank |
RHB Bank | rhb |
Standard Chartered | standard_chartered |
UOB Bank | uob |
Error codes 
These are the common error codes and corresponding recommended actions:
Error Code | Recommended Action |
---|---|
invalid_ | FPX transactions must be greater than RM2 and less than RM30,000. |
invalid_ | The provided bank is not supported by FPX. Please use one of the options from the Bank Reference above. |
invalid_ | FPX only supports MYR transactions. |
missing_ | A required parameter is missing. Please check the error_ for more information about which parameter is required. |
offline_ | The provided bank is currently offline. Please try using a different bank or payment method type. |
payment_ | The payment method is currently not available. You should invite your customer to fallback to another payment method to proceed. |
payment_ | An 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_
:
You can also retrieve your balance to see a breakdown of your available
and pending
Stripe balances by source_
.