> ## Documentation Index
> Fetch the complete documentation index at: https://flutterwaveinc.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

<iframe height="300" width="100%" scrolling="no" title="Flutterwave Inline" src="https://codepen.io/Phenzic/embed/XWLebNK?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/Phenzic/pen/XWLebNK">Flutterwave Inline</a> by Mayowa Julius (<a href="https://codepen.io/Phenzic">@Phenzic</a>)\
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<Info>
  **Try it Out**

  You can 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](/testing) page.
</Info>

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:

```html theme={null}
<script src="https://checkout.flutterwave.com/v3.js"></script>
```

2. 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.

```html theme={null}
<button type="button" onclick="makePayment()">Pay Now</button>
```

3. Finally, in the `makePayment()` function, you call the `FlutterwaveCheckout()` function with some custom parameters:

```javascript theme={null}
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: '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 the `FlutterwaveCheckout()` Function

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

| Parameters                   | Functions                                                                                                                                                                                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tx_ref`                     | A unique transaction reference you should generate for each transaction.                                                                                                                                                   |
| `amount`                     | 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.                                                                    |
| `currency`                   | The currency the amount is in. Flutterwave supports over a hundred different currencies, so be sure to specify the currency you mean.                                                                                      |
| `customer`                   | This 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_key`                 | This is your public API key. [Here's](/authentication#get-your-api-keys) 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](/payments-embed/inline#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](/payments-embed/payment-methods).                                            |

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

<Info>
  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.
</Info>

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](/payments-embed/inline#option-2-callback) instead of [redirects](/payments-embed/inline#option-1-redirect).

## 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).

<Warning>
  **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.
</Warning>

### 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:

```json theme={null}
{
	"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
}
```

<Info>
  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.
</Info>

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.

<iframe height="300" width="100%" scrolling="no" title="Untitled" src="https://codepen.io/Phenzic/embed/ExBwKwW?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/Phenzic/pen/ExBwKwW">Untitled</a> by
  Mayowa Julius (<a href="https://codepen.io/Phenzic">@Phenzic</a>) on{' '}
  <a href="https://codepen.io">CodePen</a>.
</iframe>

<Warning>
  **Always Verify your Transactions**

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

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

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):

```javascript theme={null}
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](/webhooks) for an example.

If the customer closes the payment modal, you can handle this event using the `onclose` option, described in the [next section](/payments-embed/inline/#handling-cancelled-payments).

## 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.

<Warning>
  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.
</Warning>

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.

```javascript theme={null}
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.

```javascript theme={null}
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: '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',
		},
		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](/sdk-plugins/frontend-libraries/react) page to see what's available.

## Webhooks

If you've set up [webhook notifications](/webhooks) 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:

```javascript theme={null}

{
  "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": "rose@unsinkableship.com",
      "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:

* [HTML checkout](/payments-embed/html-checkout) lets you do the same thing, but entirely in HTML.

* [Flutterwave Standard](/payment-api/flutterwave-standard) lets you control the payment flow from your server instead.

And there's more! Check out our [Payments UI and Embeds page](/payments-embed/introduction) to know your options. And if you get stuck, you can always ask for help on our [support page](https://flutterwave.com/support/submit-request).
