We recommend checking out the introductory section
to understand the basics of direct charge first. This guide assumes you’ve
read that.
The country of operation for your Flutterwave account is the country you
selected during account creation. Payments will be considered
international if you accept cards issued outside this country or charge
in currencies other than your local currency.
Prerequisite
Payment Flow
Using a card charge involves four main steps:- Initiating the payment: You send the transaction details and the customer’s payment details to the charge card endpoint.
- Authorize the charge: We tell you the details needed to authorize the charge, you get those from the customer, and you send them to the same charge card endpoint.
- Validate the charge: Think of this as a second layer of authentication. The customer provides some info to validate the charge (such as an OTP), and you send that to us (via the validate charge endpoint). This completes the payment.
- Verify the payment: As a failsafe, you’ll call our API to verify that the payment was successful before giving value (via the verify transaction endpoint).

Recurring Payments
You can also collect recurring payments from customers with direct card charges. See our guide to card tokenization.Card Authorization Models
When you make a card charge request, Flutterwave will evaluate the card to determine its authorization model—a card personal identification number (PIN), an address verification system (AVS), a 3DS redirect, or no authorization at all. If no authorization is required, the charge is completed, and you can skip to verifying the payment. For cards that require authorization, we’ll send you a prompt telling you what parameters are needed for that authorization model so the cardholder can authenticate their transaction.Collect the Customer’s Payment Details
First, you’ll need the customer’s card details. You can collect these with a simple HTML form like the one below:
After collecting the card details, you’ll need to add some other details to make up the full payload, including:
tx_ref: A unique reference code that you’ll generate for each transaction.amount: The amount to be charged for the transaction.currency: The currency to be used for the charge.email: The customer’s email address.redirect_url(optional): The url we should redirect to after the customer completes payment. For 3DSecure payments, we’ll appenddata(the transaction response data) to the URL as query parameters.meta(optional): Any extra details you wish to attach to the transaction. For instance, you could include theflight_idorproduct_url.
Request Payload
Preauthorization
Preauthorizing a card is a way to place a “hold” on the amount you plan to charge a customer. This is helpful if you intend to bill the customer after they use your service, but you want to ensure they have enough funds to pay before providing them the service. For instance, if you run a ride-hailing business or hotel, you’d typically charge the customer after their trip or stay. However, you can estimate how much the trip or stay will cost and preauthorize the charge. This will “lock” the requested amount for a maximum of 7 working days. That way, you can be sure the customer will be able to pay their bill after rendering the service.Approval RequiredUsing preauthorization requires approval. Contact us at compliance@flutterwavego.com so we can enable it on your account.
preauthorize parameter in your card charge payload.
amount you want to charge. Note that the captured amount must be less than or equal to the preauthorized amount.
External 3DS
External 3D Secure (3DS) is a feature that allows you to control how the identity of your customer (the cardholder) is verified by using a custom provider of your choice. Unlike the regular 3DS, where the identity verification process is automatically handled for you by the payment system, External 3DS gives you the flexibility to integrate and manage this verification process according to your specific needs.Approval RequiredThis feature is unavailable by default. Send us an email at hi@flutterwavego.com to enable external 3DS on your account.
Encrypt the Payload Request
If you’re using one of our backend
SDKs, you should skip this step, as
they’ll automatically encrypt the payload for you when sending the request.
Head on to the next step.
Initiate Payment
To initiate payment, send your encrypted payload to our charge card endpoint. If you’re using one of our SDKs, you’ll pass in the payload directly, and we’ll encrypt it for you. Otherwise, you can do the encryption manually as shown above, then call the endpoint:Authorize the Payment
This next step will vary depending on the type of card you’re charging. After initiating a charge, the customer may need to authorize the charge on their card. Card authorization methods are typically one of the following:- PIN: The customer enters the card PIN to authorize the payment.
- AVS (Address Verification System): The customer enters details of the card’s billing address. This is often used for international cards.
- 3DS (3D Secure): The customer needs to be redirected to a secure webpage to complete the payment.
- None: In some cases, the card may not need any authorization steps at all.
meta.authorization field. The meta.authorization.mode key indicates the type of authorization that is needed, while the meta.authorization.fields key indicates the fields you need to collect from the customer. For instance:
- If the
modeis"pin", then the card requires PIN authentication. You’ll need to collect the customer’s PIN. - If the
modeis"avs_noauth", the card requires AVS authentication. You’ll need to collect the specifiedfields(for example,city,address,state,country, andzipcode). - If the
modeis"redirect", then you won’t be collecting any extra fields. Instead, you’ll redirect to the specified URL (inmeta.authorization.redirect) for the customer to authenticate with their bank. - In some cases, the card doesn’t need any additional authentication, so you can skip to verifying the payment. In that case, the
data.statusfield will be either"successful"or"failed".
Handling 3DS Authorization
With 3DS authorization, all you’ll need to do is redirect your user to the specified redirect URL (themeta.authorization.redirect field). The user will then complete the authorization on their bank’s page, then we’ll redirect back to the redirect_url you specified initially, appending the tx_ref and status to the URL as query parameters.
Before redirecting, you should store the transaction ID returned from the
3DS response (
data.id ), as you’ll need it to
verify the payment when we redirect
back to your app.Handling PIN and AVS Authorization
With PIN and AVS authorization, you’ll need to collect the specifiedfields (i.e. the card’s PIN or address details) and add them to your initial payload (in an authorization object). Then, you’ll encrypt the new payload and send it to the same charge card endpoint.
This means you’ll be calling the charge card endpoint twice—the first time
to find out the authorization mode, and the second to authorize the charge.
Validate the Charge
After encrypting and sending the new payload, if the authorization is successful, you’ll get a response that looks like one of these:Note that even though the
status field is "success" (the charge has been
initiated), the data.status field is "pending" , meaning that the
transaction hasn’t yet been approved by the customer. You’ll need to
validate the transaction to complete it.meta.authorization.mode field:
redirect: in this case, you’ll get aprocessor_responsemessage saying"Pending Validation". You’ll need to redirect your customers to the returned link where they can complete the payment. Afterwards, we’ll redirect the customer back to theredirect_urlyou specified earlier, with atx_refandstatus. This means you don’t need to do anything else, and your redirect handler can skip to verifying the payment.otp: This means an OTP has been sent to your customer’s mobile phone. Theprocessor_responsewill contain instructions you can display to the cardholder. When the user enters the OTP, you’ll need to validate the transaction by calling our validate charge endpoint with the customer’s OTP and theflw_reffor the transaction (which was returned in the earlier response).
Validation Successfully
data.status field indicates that the charge was successful. However, as a safety measure, always verify the payment.
Handling Redirects
When redirecting users, the URL structure typically places the query string before the fragment identifier (#). This is standard web behavior and may cause errors if your application relies on the hash for routing.
Redirects as a POST Request
To ensure that a redirect is performed using a POST request instead of the default GET request, append #redirect_as_post to theredirect_url.
- If your
redirect_urlis a frontend application:- The POST request body will not be accessible directly.
- We recommend the use of webhooks or the verify endpoint to retrieve the transaction status after the redirect.
- If the
redirect_urlis a backend system:- The backend can process both GET and POST requests, making the request body accessible.
Redirects using Ignore_Opener
If you experience issues when redirecting your users to new windows/tabs, e.g. redirect within single-page applications (SPAs), append #ignore_opener to theredirect_url.
This prevents the redirected page from accessing the window.opener property, ensuring it opens separately and can’t immediately redirect to a malicious URL.
Verify the Payment
Almost done! The last step is to verify that the payment was successful before giving value to your customer. To do so, call our verify transaction endpoint with yourtransaction_id. See our guide on transaction verification for more details.
data.status field is now "successful".
Payment Successful
Examples
Putting it all together, here’s what an implementation of direct card charge might look like:Webhooks
You can also verify the payment in a webhook handler. Here’s an example of the payload we send to your webhook for successful card charges. The event type ischarge.completed and the data object contains the transaction information.