Inertia (React, Vue, Svelte)
The package ships typed components for Inertia apps in React 18/19, Vue 3 and Svelte 5, tested against Inertia 1, 2 and 3. They use Flutterwave's look and load the checkout script for you.
Publish the components
Pick one framework:
php artisan flutterwave:install --react
php artisan flutterwave:install --vue
php artisan flutterwave:install --svelteThey're copied to resources/js/components/flutterwave, so they're yours to edit, and import from @/components/flutterwave.
The pay button
Build the checkout config on the server with inlineConfig(), so the amount can't be changed in the browser, and pass it as a prop:
use Flutterwave\Payments\Facades\Flutterwave;
use Inertia\Inertia;
public function show(Order $order)
{
return Inertia::render('Checkout', [
'checkout' => Flutterwave::inlineConfig([
'tx_ref' => $order->reference,
'amount' => $order->total,
'currency' => $order->currency,
'email' => $order->user->email,
]),
]);
}import { router } from '@inertiajs/react';
import { FlutterwavePayButton, type FlutterwaveCheckoutConfig } from '@/components/flutterwave';
export default function Checkout({ checkout }: { checkout: FlutterwaveCheckoutConfig }) {
return (
<FlutterwavePayButton
config={checkout}
onSuccess={(payment) => router.post('/orders/confirm', { transaction_id: payment.transaction_id })}
onClose={(incomplete) => incomplete && console.log('Customer left without paying')}
>
Pay now
</FlutterwavePayButton>
);
}<script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { FlutterwavePayButton, type FlutterwaveCheckoutConfig } from '@/components/flutterwave';
defineProps<{ checkout: FlutterwaveCheckoutConfig }>();
</script>
<template>
<FlutterwavePayButton
:config="checkout"
:on-success="(payment) => router.post('/orders/confirm', { transaction_id: payment.transaction_id })"
>
Pay now
</FlutterwavePayButton>
</template><script lang="ts">
import { router } from '@inertiajs/svelte';
import { FlutterwavePayButton, type FlutterwaveCheckoutConfig } from '@/components/flutterwave';
let { checkout }: { checkout: FlutterwaveCheckoutConfig } = $props();
</script>
<FlutterwavePayButton
config={checkout}
onSuccess={(payment) => router.post('/orders/confirm', { transaction_id: payment.transaction_id })}
>
Pay now
</FlutterwavePayButton>Passing onSuccess keeps the customer on your page (Flutterwave ignores callbacks when a redirect_url is set, so the component drops it). Leave onSuccess out to use the redirect instead. Either way, verify the payment on your server.
Your own button
In React and Vue, useFlutterwaveCheckout() loads the script and tells you when it's ready:
import { useFlutterwaveCheckout } from '@/components/flutterwave';
const { open, ready, error } = useFlutterwaveCheckout();
open(checkout, { onSuccess, onClose });In Svelte, or anywhere else, call the plain functions:
import { loadFlutterwave, openCheckout } from '@/components/flutterwave';
await loadFlutterwave();
openCheckout(checkout, { onSuccess, onClose });Hosted checkout from an Inertia form
Flutterwave::redirect() notices Inertia's XHR requests and returns a 409 with X-Inertia-Location, so router.post('/pay') leaves for Flutterwave's page without extra code.
Other components
The same folder has the components behind the admin page: Transactions, Refunds, Settlements, Chargebacks, Beneficiaries, FxConverter, VirtualAccount and BankSelect. Each takes the matching panel() data as a prop.