Flutterwave Inline

Start integrating Flutterwave with a few lines of code.

Flutterwave Inline is the easiest way to receive payments on your website. Simply import our lightweight JavaScript library on your checkout page, and call the FlutterwaveCheckout() function when your customer clicks the payment button. We'll handle the payment process and notify you once it's complete.

An Example

📘

Try it Out

You can try out the payment above. Use the card number4187427415564246 with CVV 828 and expiry 09/32, or grab a test card or bank account from our Testing page.

Let's take a closer look at the key things this code does:

  1. First, you include the Flutterwave Inline library with a script tag:
<script src="https://checkout.flutterwave.com/v3.js"></script>
  1. Next is the payment button. This is the button the customer clicks after they've reviewed their order and are ready to pay you. You'll attach an onclick event handler to this button and call the makePayment() function.
<button type="button" onclick="makePayment()">Pay Now</button>
  1. Finally, in the makePayment() function, you call the FlutterwaveCheckout() function with some custom parameters:
function makePayment() {
	FlutterwaveCheckout({
		public_key: 'FLWPUBK_TEST-SANDBOXDEMOKEY-X',
		tx_ref: 'titanic-48981487343MDI0NzMx',
		amount: 54600,
		currency: 'NGN',
		payment_options: 'card, mobilemoneyghana, ussd',
		redirect_url: 'https://glaciers.titanic.com/handle-flutterwave-payment',
		meta: {
			consumer_id: 23,
			consumer_mac: '92a3-912ba-1192a',
		},
		customer: {
			email: '[email protected]',
			phone_number: '08102909304',
			name: 'Rose DeWitt Bukater',
		},
		customizations: {
			title: 'The Titanic Store',
			description: 'Payment for an awesome cruise',
			logo: 'https://www.logolynx.com/images/logolynx/22/2239ca38f5505fbfce7e55bbc0604386.jpeg',
		},
	});
}

Calling the FlutterwaveCheckout() Function

Let's take a closer look at the parameters we passed when calling FlutterwaveCheckout():

ParametersFunctions
tx_refA unique transaction reference you should generate for each transaction.
amountThe amount the customer is to pay. In this case, we're hardcoding it, but you could also dynamically get it from your server or client-side JavaScript.
currencyThe currency the amount is in. Flutterwave supports over a hundred different currencies, so be sure to specify the currency you mean.
customerThis field holds the customer details. The email field is required (we'll send the customer a payment receipt afterward unless you've disabled that). You can also pass in a name and phone_number.
public_keyThis is your public API key. Here's how to get it.
meta (optional)This will hold any extra details you want to record with the transaction.
redirect_url (optional)This is the URL we'll redirect to on your site after the payment is done. Alternatively, you can specify a callback function. See the redirects and callbacks section.
customizations (optional)This allows you to customize the look and feel of the payment modal. You can set a logo, the store name to be displayed (title), and a description for the payment.
payment_options (optional)This allows you to specify what payment methods you want to allow payments from. Learn more about this field and the available options here.

🚧

Public Key

Don't forget that this is client-side code, so it uses your public key, not your secret key.

ℹ️

Generating Transaction Reference

We also recommend generating the transaction reference (tx_ref) on the server, so you can compare with previous transactions to be sure there are no duplicates.

The call to FlutterwaveCheckout() returns a JavaScript object with a close() method that can be used to close the modal, which can be useful if you are using callbacks instead of redirects.

Redirects and Callbacks

After calling the FlutterwaveCheckout() function and the payment is done, you can do one of the following:

Option 1: Redirect

If you specify a redirect_url when calling FlutterwaveCheckout() (like in our example above), we'll redirect the customer to that URL when the payment is made. We'll append your transaction reference, our transaction ID, and status to the URL like this: tx_ref=ref&transaction_id=30490&status=successful.

On your server, you should handle the redirect and always verify the final state of the transaction.

🚧

Transaction Verification must be Server-Side

Transaction verification should always be done on the server, as it makes use of your secret key, which should never be exposed publicly.


Option 2: Callback

Alternatively, you can specify a callback instead. In this case, you'll specify a JavaScript function that we'll call when the payment is made, passing in the payment object. Here's what that object looks like:

{
	"amount": 54600,
	"currency": "NGN",
	"customer": {
		"name": "Rose DeWitt Bukater",
		"email": "[email protected]",
		"phone_number": "08102909304"
	},
	"flw_ref": "FLW-MOCK-597ae423f1470309edcb5879e3774bfa",
	"status": "successful",
	"tx_ref": "titanic-48981487343MDI0NzMx",
	"transaction_id": 495000
}

ℹ️

Note

Note that the callback will be called after the payment is completed, but while the modal is still open. You can combine the callback with the onclose handler for a better experience.

Here's an example that uses a callback and onclose function. The callback function sends a verification request to the backend in the background. Then, when the customer closes the modal, the onclose function displays a "verifying" message if the background request is not complete or a thank-you message if the verification was successful. If the verification fails, the customer will be asked to try again or contact support.

❗️

Always Verify your Transactions

You should always verify the payment on your server afterwards, even if you used a callback.

🚧

Note

The redirect_url has higher precedence than the callback, so if you specify both, we'll use the redirect.

You can also use the callback option to manually close the modal with the modal's close() method (this won't trigger the onclose handler):

function makePayment() {
	const modal = FlutterwaveCheckout({
		// ...
		callback: function (payment) {
			// Send AJAX verification request to backend
			verifyTransactionOnBackend(payment.id);
			modal.close();
		},
	});
}

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.

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.

If the customer closes the payment modal, you can handle this event using the onclose option, described in the next section.

Handling Cancelled Payments

If the customer closes the payment modal before making payment or clicks Cancel Payment, we'll cancel the payment session, hide the modal, and you won't be notified. You can specify an onclose function. We'll call this function when the payment is cancelled, with a single boolean argument that's true if the payment was not completed.

🚧

Payment Modal

If a customer closes the payment modal while the payment is processing, the payment will be marked as cancelled, but the payment session won't be aborted. If the transaction ends up succeeding later, webhooks, customer notifications, and the like will be triggered.

An example of when you might want to use this is to send such events to your analytics service or reach out to customers who didn't complete their orders.

function makePayment() {
	FlutterwaveCheckout({
		public_key: 'FLWPUBK_TEST-SANDBOXDEMOKEY-X',
		// ...
		onclose: function (incomplete) {
			if (incomplete === true) {
				// Record event in analytics
			}
		},
	});
}

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 cancelled and marked as failed.

The timeout can be set to a max value of 1440 minutes.

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 at checkout. When making a payment, the transaction would be cancelled and marked as failed if the user attempts to reach max retry.

Using these configurations can help you improve security on checkout by limiting malicious users' payment attempts. For example, If timeout and retry for a transaction are set to 10 minutes and five (5) attempts, respectively. The transaction fails automatically if the user makes more than five attempts or spends longer than 10 minutes to complete the transaction.

function makePayment() {
	FlutterwaveCheckout({
		public_key: 'FLWPUBK_TEST-SANDBOXDEMOKEY-X',
		tx_ref: 'titanic-48981487343MDI0NzMx',
		amount: 54600,
		currency: 'NGN',
		payment_options: 'card, mobilemoneyghana, ussd',
		redirect_url: 'https://glaciers.titanic.com/handle-flutterwave-payment',
		meta: {
			consumer_id: 23,
			consumer_mac: '92a3-912ba-1192a',
		},
		customer: {
			email: '[email protected]',
			phone_number: '08102909304',
			name: 'Rose DeWitt Bukater',
		},
		customizations: {
			title: 'The Titanic Store',
			description: 'Payment for an awesome cruise',
			logo: 'https://www.logolynx.com/images/logolynx/22/2239ca38f5505fbfce7e55bbc0604386.jpeg',
		},
		configurations: {
			session_duration: 10, //Session timeout in minutes (maxValue: 1440 minutes)
			max_retry_attempt: 5, //Max retry (int)
		},
	});
}

Framework Integrations

If you're using a frontend JS framework, we've got custom integrations to ensure the payment flow plays nice with your framework. Check out our frontend libraries page to see what's available.

Webhooks

If you've set up webhook notifications for your account, we'll send you a webhook when the payment is completed, as well as for each failed payment attempt. Here's what the webhook payload looks like:


{
  "event": "charge.completed",
  "data": {
    "id": 408043532,
    "tx_ref": "titanic-48981487343MDI0NzMx",
    "flw_ref": "EJEZ7971570422814",
    "device_fingerprint": "7852b6c97d67edce50a5f1e540719e39",
    "amount": 54600,
    "currency": "NGN",
    "charged_amount": 54600,
    "app_fee": 0.14,
    "merchant_fee": 0,
    "processor_response": "APPROVED",
    "auth_model": "NOAUTH",
    "ip": "72.140.222.142",
    "narration": "CARD Transaction ",
    "status": "successful",
    "payment_type": "card",
    "created_at": "2021-04-16T11:10:02.000Z",
    "account_id": 82913,
    "customer": {
      "id": 255101610,
      "name": "Rose DeWitt Bukater",
      "phone_number": "08102909304",
      "email": "[email protected]",
      "created_at": "2021-04-16T11:10:02.000Z"
    },
    "card": {
      "first_6digits": "539923",
      "last_4digits": "2526",
      "issuer": "MASTERCARD FIRST BANK OF NIGERIA PLC DEBIT CARD",
      "country": "NG",
      "type": "MASTERCARD",
      "expiry": "01/23"
    }
  },
  "event.type": "CARD_TRANSACTION"
}

Next Steps

All done! Now you know how to collect payments with Flutterwave Inline.

If the JS-based flow doesn't work for you, there are other options:

And there's more! Check out our Payments UI and Embeds page to know your options. And if you get stuck, you can always ask for help on our support page.