Flutterwave Standard
Flutterwave Standard is our "standard" payments flow. Here's how it works:
- From your server, call our create payment endpoint with the payment details.
- We'll return a link to a payment page. Redirect your customer to this link to make the payment.
- When the transaction is completed, we'll redirect the customer back to you.
Step 1: Assemble payment details
First, you need to assemble the payment details. Here are the details you'll need:
-
tx_ref
: A reference code you'll generate to identify this transaction. This must be unique for every transaction -
amount
: The amount to charge the customer. -
currency
: The currency to charge in. If you don't specify a value, we'll assume"NGN"
-
redirect_url
: The URL to redirect the customer to after payment is done. -
customer
: An object containing the customer details. Anemail
is required, and you can also pass aname
andphonenumber
-
meta
(optional): An object containing any extra information you'd like to store alongside the transaction e.g{consumer_id: 23, consumer_mac: '92a3-912ba-1192a'}
-
customizations
(optional): An object containing options to customize the look of the payment modal. You can set atitle
,logo
, anddescription
-
subaccounts
(optional): An array of objects containing the subaccount IDs to split the payment into. See Split payment for more on this. -
payment_options
(optional): The payment options to be displayed. See Payment methods.The
payment_options
field only works if you've unchecked Enable Dashboard Payment Options on your Account Settings. -
payment_plan
(optional): The payment plan ID (for when you're collecting a recurring payment) -
The
session_duration
field (optional) allows you to set the session in minutes with a maximum value of 1440 minutes (24hrs). -
The
max_retry_attempt
field (optional) allows you to set the maximum number of times a customer can retry after a failed transaction before the checkout is closed.
Step 2: Get a payment link
Next, you'll initiate the payment by calling our API with the collected payment details (remember to authorize with your secret key). Here's an example in Node.js
const got = require("got");
try {
const response = await got.post("https://api.flutterwave.com/v3/payments", {
headers: {
Authorization: `Bearer ${process.env.FLW_SECRET_KEY}`
},
json: {
tx_ref: "hooli-tx-1920bbtytty",
amount: "100",
currency: "NGN",
redirect_url: "https://webhook.site/9d0b00ba-9a69-44fa-a43d-a82c33c36fdc",
meta: {
consumer_id: 23,
consumer_mac: "92a3-912ba-1192a"
},
customer: {
email: "user@gmail.com",
phonenumber: "080****4528",
name: "Yemi Desola"
},
customizations: {
title: "Pied Piper Payments",
logo: "http://www.piedpiper.com/app/themes/joystick-v27/images/logo.png"
}
}
}).json();
} catch (err) {
console.log(err.code);
console.log(err.response.body);
}
And you'll get a response like this:
{
"status": "success",
"message": "Hosted Link",
"data": {
"link": "https://api.flutterwave.com/v3/hosted/pay/f524c1196ffda5556341"
}
}
Step 3: Redirect the user to the payment link
Now all you need to do is redirect your customer to the link returned in data.link
, and we'll display our checkout modal for them to complete the payment.
Step 4: After the payment
Four things will happen when payment is done (successful):
- We'll redirect to your
redirect_url
withstatus
,tx_ref
, andtransaction_id
query parameters after payment is complete. - We'll send you a webhook if you have that enabled. Learn more about webhooks and see examples here.
- We'll send an email receipt to your customer if the payment was successful (unless you've disabled that).
- We'll send you an email notification (unless you've disabled that).
On your server, you should handle the redirect and always verify the final state of the transaction.
Here's what transaction verification could look like in a Node.js app with our backend SDK:
app.get('/payment-callback', async (req, res) => {
if (req.query.status === 'successful') {
const transactionDetails = await Transaction.find({ref: req.query.tx_ref});
const response = await flw.Transaction.verify({id: req.query.transaction_id});
if (
response.data.status === "successful"
&& response.data.amount === transactionDetails.amount
&& response.data.currency === "NGN") {
// Success! Confirm the customer's payment
} else {
// Inform the customer their payment was unsuccessful
}
}
);
What if the payment fails?
If the payment attempt fails (for instance, due to insufficient funds), you don't need to do anything. We'll keep the payment page open, so the customer can try again until the payment succeeds or they choose to cancel, after which we'll redirect to the redirect_url
with the query parameters tx_ref
and a status
of failed
.
If you have webhooks enabled, we'll send you a notification for each failed payment attempt. This is useful in case you want to later reach out to customers who had issues paying. See our webhooks guide for an example.
Handling payment retries and timeout on Checkout
Flutterwave allows you to configure retries and timeout on checkout to further improve your customers' experience. Timeouts help you limit the completion time for each payment. Once the timeout period is completed, the payment window is closed, and the user is redirected to the specified URL (redirect_url). Uncompleted transactions are canceled and marked as failed.
Timeout can be set to a max value of 1440 minutes or 24 hours.
Additionally, You can limit how many attempts users make for failed transactions on checkout. By setting max_retry
, The user is prevented from attempting transactions unnecessarily on checkout. When making a payment, the transaction would be canceled and marked as failed, if the user attempts reaches max retry.
Using these configurations can help you improve security on checkout by limiting payment attempts of malicious users. For example, If timeout and retry for a transaction are set to 10 mins and five (5) attempts respectively, The transaction fails automatically if the user makes more than five attempts or spends longer than 10 mins to complete the transaction.
const got = require("got");
try {
const response = await got.post("https://api.flutterwave.com/v3/payments", {
headers: {
Authorization: `Bearer ${process.env.FLW_SECRET_KEY}`
},
json: {
tx_ref: "hooli-tx-1920bbtytty",
amount: "100",
currency: "NGN",
redirect_url: "https://webhook.site/9d0b00ba-9a69-44fa-a43d-a82c33c36fdc",
meta: {
consumer_id: 23,
consumer_mac: "92a3-912ba-1192a"
},
customer: {
email: "user@gmail.com",
phonenumber: "080****4528",
name: "Yemi Desola"
},
customizations: {
title: "Pied Piper Payments",
logo: "http://www.piedpiper.com/app/themes/joystick-v27/images/logo.png"
},
configurations: {
session_duration: 10, //Session timeout in minutes (maxValue: 1440 minutes)
max_retry_attempt: 5, //Max retry (int)
}
}
}).json();
} catch (err) {
console.log(err.code);
console.log(err.response.body);
}