Set Up Flutterwave Payments
Selling across Africa means buyers who pay by mobile money in one country, bank transfer in the next and card in a third, in a dozen currencies. One gateway per country is a lot of settings screens to keep working.
Flutterwave covers those methods on one hosted checkout. The Flutterwave module adds it to WooCommerce for one-time payments: each payment is verified with Flutterwave before the order is marked paid, refunds go back through Flutterwave, and webhooks bring in payments and refunds made in Flutterwave.
Currencies
Flutterwave shows at checkout when the order is in one of these currencies:
- African currencies: NGN, GHS, KES, UGX, TZS, RWF, ZAR, XAF, XOF, MWK, ZMW and EGP
- International: USD, EUR and GBP
Which of them your account can take, and which methods buyers see, depends on your Flutterwave account’s country and settings. UGX, RWF, XAF and XOF are sent as whole numbers.
Flutterwave works with Multi-Currency Checkout, and Currency-Aware Payment Gateways knows its list.
Turn On the Gateway
- Switch on the Flutterwave module under Stackless → Dashboard.
- Go to WooCommerce → Settings → Payments → Flutterwave (Stackless).
- Tick Enable (Accept payments with Flutterwave).
Stackless → Settings → Flutterwave only shows a link to that screen and your webhook URL. Flutterwave stays off the checkout until the current mode has a secret key.
Add Your API Keys
This gateway uses Flutterwave’s v3 API, its stable one. In the Flutterwave dashboard, open Settings → API Keys and copy the v3 secret key. If the dashboard offers “Switch to v4 live API keys”, stay on v3. Copy the test key with the dashboard in test mode. The Get API keys button opens the live keys page. Then fill in:
- Test mode: on by default. No real money moves.
- Live secret key and Live webhook secret hash
- Test secret key and Test webhook secret hash
Test keys start with FLWSECK_TEST. When you save, Stackless checks each new key with Flutterwave and shows an error if Flutterwave rejects it, or if a key sits in the other mode’s field. The public key isn’t needed.
You can also set these as wp-config.php constants, which win over saved settings and hide their fields: STACKLESS_FLUTTERWAVE_LIVE_SECRET_KEY, STACKLESS_FLUTTERWAVE_LIVE_SECRET_HASH, STACKLESS_FLUTTERWAVE_TEST_SECRET_KEY and STACKLESS_FLUTTERWAVE_TEST_SECRET_HASH.
Connect the Webhook
Flutterwave doesn’t hand you a webhook secret. You make one up, any long random text, and enter it in both places:
- Type it into the webhook secret hash field for the mode and save.
- In Flutterwave, open Settings → Webhooks, once in test mode and once in live mode. The Open webhook settings button opens the live screen.
- Choose the V3 webhook and paste
https://yoursite.com/wp-json/stackless/v1/flutterwave/webhook. The gateway settings show your exact URL. - Enter the same text as the Secret hash.
- Tick every box on that screen, including Receive webhook response in JSON format, Enable webhook retries and Enable webhook for refunds, then save.
Flutterwave sends the secret hash back in the verif-hash header of every delivery, and Stackless compares it with your live and test hashes. Accounts whose webhooks were moved to v4 send a flutterwave-signature header instead, an HMAC-SHA256 of the raw body keyed with the same hash, and that’s accepted too. A delivery with a missing or wrong hash is refused.
Stackless acts on charge.completed deliveries and on refund deliveries, and applies each one once, however often Flutterwave retries it. Without a secret hash every webhook is refused and payments are confirmed only when buyers come back to your store, so saving with the gateway on and no hash shows an error.
What Buyers See
At checkout, Flutterwave shows as “Card, bank transfer or mobile money (Flutterwave)” with “You’ll finish paying on Flutterwave’s secure checkout.” Test mode adds “Test mode: no real payment will be taken.” It works in the Checkout block, the classic checkout and the order payment page.
- Placing the order sends the buyer to Flutterwave’s hosted checkout, titled with your store name and the order number. Their email, name and phone number are passed along.
- A completed payment lands on the order received page.
- A failed or cancelled payment sends the buyer back to the order payment page to try again.
- A payment Flutterwave is still processing lands on the order received page, and the webhook confirms it later.
- Flutterwave needs a valid email address on the order. Placing the same order again within 30 minutes reuses the open payment link.
How Payments Are Verified
Every path that can pay an order, whether the buyer’s return, the webhook or a repeated checkout, reads the transaction from Flutterwave’s API first. Stackless then checks that:
- its reference was made for this order on this site
- its status is successful
- it was made in the same mode as the order
- its currency and amount match the order total exactly
A transaction that passes marks the order paid, with a note naming the reference and payment type. A mismatch puts the order on hold with a note to check it in Flutterwave. A failed payment reported by webhook adds a note with Flutterwave’s reason. On the order screen, the transaction ID links to the transaction in your Flutterwave dashboard.
Refunds
- Refunds from the WooCommerce order screen, partial or full, are made in Flutterwave, with your refund reason sent as the comment.
- Refunds made in the Flutterwave dashboard are recorded on the order once, after Stackless reads the refund back from Flutterwave. This needs Enable webhook for refunds ticked. Items aren’t restocked.
- If Flutterwave can’t complete a refund made from WooCommerce, an order note says the money didn’t reach the customer, so you can refund another way.
Subscriptions With Flutterwave
Flutterwave takes one-time payments. It doesn’t save a payment method for Stackless to charge later, so subscriptions bought with it renew by pay link. The product’s Renewal mode decides whether Flutterwave shows:
- Automatic only hides Flutterwave at checkout.
- Automatic when the gateway supports it, otherwise manual shows Flutterwave, and paying with it makes the subscription manual.
- Manual only shows Flutterwave as usual.
At each renewal the customer gets the Subscription renewal invoice email with a link to pay the renewal order. They can pay it with Flutterwave or any other available method, and paying reactivates the subscription if it went on hold. See Create Subscription Products and Renewals, Failed Payments and Retries for grace periods and reminders.
Check the Connection
- Billing Health lists Flutterwave setup problems: no secret key for the current mode, a key for the other mode, no webhook secret hash, no webhook received yet, and test mode left on. It also shows recent webhook events that failed.
- Turn on Debug log to write Flutterwave activity to WooCommerce → Status → Logs (
stackless-flutterwave_gateway). Keys are never logged.
Limits
- One-time payments only. Subscriptions renew by emailed invoice, never automatically.
- Uses Flutterwave’s v3 API. Keep the account’s API keys and webhooks on v3.
- The webhook and its secret hash have to be set in the Flutterwave dashboard by hand.
- Which currencies and methods work depends on the account’s country and settings.
- Buyers always pay on Flutterwave’s hosted page. There’s no popup on your own checkout.
- Flutterwave isn’t used for orders with nothing to pay, and can’t be duplicated for a second account with Payment Gateway Tools.
For Developers
stackless_flutterwave_gateway_checkout_args changes the payment sent to Flutterwave and receives the body, the order and the gateway. stackless_flutterwave_gateway_currencies changes the currency list. The stackless_flutterwave_gateway_webhook action runs after each applied delivery with the event type, its data and the mode. To show your logo on Flutterwave’s checkout:
add_filter('stackless_flutterwave_gateway_checkout_args', function ($args, $order, $gateway) {
$args['customizations']['logo'] = 'https://yoursite.com/logo.png';
return $args;
}, 10, 3);
Override the checkout fields by copying the template to yourtheme/stackless/flutterwave_gateway/payment-fields.php.