Flutterwave Inline

Flutterwave Inline is the easiest way to collect payments on your website: Import our lightweight JavaScript library on your checkout page, then call the FlutterwaveCheckout() function when the customer clicks on your payment button. We'll handle the payment and return to you when it's done.

In this guide, we'll walk you through using Flutterwave Inline on your site.

An example

Here's what an implementation of Flutterwave Inline on a checkout page could look like:

See the Pen Flutterwave Inline (Redirect) by Shalvah (@shalvah) on CodePen.

Try it out😀

You can actually try out the payment above. Use the card number 4187427415564246 with CVV 828 and expiry 09/32, or grab a test card or bank account from our Testing Helpers page. It works!

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

  • First, you include the Flutterwave Inline library with a script tag:

    <script src="https://checkout.flutterwave.com/v3.js"></script>
  • Next up 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 that calls makePayment(), a custom JS function you're going to write.

    <button type="button" onclick="makePayment()">Pay Now</button>
  • Finally, in the makePayment() function, you call the FlutterwaveCheckout() function with some custom parameters:

    function makePayment() {
        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: "rose@unsinkableship.com",
          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 FlutterwaveCheckout()

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

  • The public_key is your Flutterwave public API key. Here's how to get it.

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

  • The tx_ref is a unique transaction reference you should generate for each transaction.

    We recommend generating the transaction reference on the server, so you can compare with previous transactions to be sure there are no duplicates.
  • The amount is the 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.

  • The currency is the currency the amount is in. Flutterwave supports over a hundred different currencies, so be sure to specify the currency you mean.

  • The redirect_url field (optional) 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.

    What is a "done" payment?

    On Flutterwave Inline, a done payment is a successful payment. This is because we don't end the payment session if the payment attempt fails; we keep it open for the customer to try again. We only redirect or callback when the payment succeeds.

  • The customer field holds the customer details. The email field is required (we'll send the customer a payment receipt afterwards, unless you've disabled that). You can also pass in a name and phone_number.

  • The meta field (optional) holds any extra details you want to record with the transaction.

  • The customizations field (optional) 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.

  • The payment_options field (optional) allows you to specify what payment methods you want to allow payments from. Learn more about this field and the available options here.

    The payment_options field only works if you've unchecked Enable Dashboard Payment Options on your Account Settings.

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're using a callback instead of a redirect.

Redirects and callbacks

Alright, so now you've called FlutterwaveCheckout(). What happens when the payment is done?

One of two things can happen: redirect or callback. You choose.

Option 1: Redirect

If you specify a redirect_url when calling FlutterwaveCheckout() (as we did in our example above), we'll redirect the customer to that URL when the payment is done. 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 done, passing in the payment object. Here's what that object looks like:

  "amount": 54600,
  "currency": "NGN",
  "customer": {
    "name": "Rose DeWitt Bukater",
    "email": "rose@unsinkableship.com",
    "phone_number": "08102909304"
  "flw_ref": "FLW-MOCK-597ae423f1470309edcb5879e3774bfa",
  "status": "successful",
  "tx_ref": "titanic-48981487343MDI0NzMx",
  "transaction_id": 495000

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 failed, it will ask the customer to try again or contact support.

See the Pen Flutterwave Inline (Callback) by Shalvah (@shalvah) on CodePen.

Always verify the transaction

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

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

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. If you do want to be notified, though, 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.

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() {
      // ...
      onclose: function(incomplete) {
          if (incomplete === true) {
            // Record event in analytics

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.


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": "",
    "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": "rose@unsinkableship.com",
      "created_at": "2021-04-16T11:10:02.000Z"
    "card": {
      "first_6digits": "539923",
      "last_4digits": "2526",
      "country": "NG",
      "type": "MASTERCARD",
      "expiry": "01/23"
  "event.type": "CARD_TRANSACTION"

Moving on from here...

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

If the JS-based flow doesn't work for you, we've got other options:

And there's more! Check out our Collecting Payments overview to know your options. And if you get stuck, you can always ask for help on our developer forum.