We recently rolled out a new version of our payment APIs to make payments simpler for Flutterwave merchants and their customers. Our V4 APIs are built to help developers and businesses easily integrate secure, reliable payment solutions into their websites, products, and applications.
This guide covers key features like payment models, transaction handling, and flexible integration options. Whether you're building a new payment platform or improving an existing one, v4 provides the tools to streamline your workflow while maintaining top-tier security and reliability.
By the end of this guide, you'll understand what the v4 APIs are, their advantages, how to charge a card using them, the supported flows, and when to use each flow.
Before we dive into v4, let’s take a quick look at how card payments work in v3 and the common challenges users face. Understanding these pain points will highlight how v4 makes payment processing smoother and more efficient.
How Card Payments Work in v3
Below is an overview of how card payment works:
- Customer Initiates Payment: The customer enters their card details on the merchant's platform.
- Merchant Processes and Sends Data: The merchant encrypts the card details and transaction information and then sends them to Flutterwave.
- Flutterwave Forwards the Transaction: Flutterwave securely sends the transaction details to the acquiring bank.
- Transaction Passes Through Card Scheme: The acquiring bank forwards the transaction to the card scheme, which communicates with the issuing bank.
- Issuing Bank Approves or Declines: The issuing bank verifies funds, checks for restrictions, authenticates the transaction, and approves or declines it.
- Final Confirmation and Settlement: The approval flows back through the same channels to Flutterwave, the merchant is notified, and the transaction is settled.
To charge a card, you’ll do the following:
Initiate a Charge
First, you’ll need to collect the customer's details and card information and encrypt them as the payload. You’ll also need your encryption key from your dashboard.
// Sample of a helper function to encrypt payload
function encrypt(encryptionKey, payload) {
const text = JSON.stringify(payload);
const forge = require('node-forge');
const cipher = forge.cipher.createCipher(
'3DES-ECB',
forge.util.createBuffer(encryptionKey),
);
cipher.start({ iv: '' });
cipher.update(forge.util.createBuffer(text, 'utf-8'));
cipher.finish();
const encrypted = cipher.output;
return forge.util.encode64(encrypted.getBytes());
}
Lastly, you’ll then charge your customer by passing the encrypted payload as a client parameter and sending a request to the card endpoint.
curl --request POST \
--url https://api.flutterwave.com/v3/charges?type=card \
--header 'Authorization: Bearer <FLW_SECRET_KEY>' \
--header 'content-type: application/json' \
--data '{ "client": "Of8p6iJUVUezgvjUkjjJsP8aPd6CjHR3f9ptHiH5Q0+2h/FzHA/X1zPlDmRmH5v+GoLWWB4TqEojrKhZI38MSjbGm3DC8UPf385zBYEHZdgvQDsacDYZtFEruJqEWXmbvw9sUz+YwUHegTSogQdnXp7OGdUxPngiv6592YoL0YXa4eHcH1fRGjAimdqucGJPurFVu4sE5gJIEmBCXdESVqNPG72PwdRPfAINT9x1bXemI1M3bBdydtWvAx58ZE4fcOtWkD/IDi+o8K7qpmzgUR8YUbgZ71yi0pg5UmrT4YpcY2eq5i46Gg3L+fxFl4tauG9H4WBChF0agXtP4kjfhfYVD48N9Hrt"}'
However, if you use any of our SDKs, you don’t need to manually encrypt the payload before making a request. Just pass in the payload as you initiate the charge, and we’ll encrypt it.
// Installation: npm i flutterwave-node-v3
const Flutterwave = require('flutterwave-node-v3');
const flw = new Flutterwave(
process.env.FLW_PUBLIC_KEY,
process.env.FLW_SECRET_KEY,
);
const payload = {
card_number: '5531886652142950',
expiry_month: '09',
expiry_year: '32',
cvv: '564',
currency: 'NGN',
amount: '7500',
email: 'developers@flutterwavego.com',
fullname: 'Flutterwave Developers',
phone_number: '+2349012345678',
tx_ref: 'UNIQUE_TRANSACTION_REFERENCE',
redirect_url: 'https://example_company.com/success',
enckey: process.env.FLW_ENCRYPTION_KEY,
};
flw.Charge.card(payload).then((response) => console.log(response));
You’ll get a response similar to this:
{
"status": "success",
"message": "Charge initiated",
"data": {
"id": 288192886,
"tx_ref": "LiveCardTest",
"flw_ref": "YemiDesola/FLW275389391",
"device_fingerprint": "N/A",
"amount": 100,
"charged_amount": 100,
"app_fee": 1.4,
"merchant_fee": 0,
"processor_response": "Kindly enter the OTP sent to *******0328",
"auth_model": "PIN",
"currency": "NGN",
"ip": "::ffff:10.7.214.204",
"narration": "CARD Transaction ",
"status": "pending",
"auth_url": "N/A",
"payment_type": "card",
"fraud_status": "ok",
"charge_type": "normal",
"created_at": "2020-07-15T14:06:55.000Z",
"account_id": 17321,
"customer": {
"id": 216517630,
"phone_number": null,
"name": "Yemi Desola",
"email": "usef@gmail.com",
"created_at": "2020-07-15T14:06:55.000Z"
},
"card": {
"first_6digits": "123456",
"last_4digits": "2343",
"issuer": "MASTERCARD GUARANTY TRUST BANK Mastercard Naira Debit Card",
"country": "NG",
"type": "MASTERCARD",
"expiry": "08/22"
}
},
"meta": {
"authorization": {
"mode": "otp",
"endpoint": "/v3/validate-charge"
}
}
}
Authorize the Payment
Depending on the type of card you’re charging, you’ll authorize the card using any of the following methods:
- 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.
The response you get from the initiate charge step determines the kind of authorization method you’ll use. For example, a PIN authorization will look like this:
{
"status": "success",
"message": "Charge authorization data required",
"meta": {
"authorization": {
"mode": "pin",
"fields": ["pin"]
}
}
}
The meta.authorization field tells you the required authorization.
To authorize the charge, you’ll call the card endpoint again by encrypting the previous payload and the required authorization method (PIN in this case).
// Installation: npm i flutterwave-node-v3
const Flutterwave = require('flutterwave-node-v3');
const flw = new Flutterwave(process.env.FLW_PUBLIC_KEY, process.env.FLW_SECRET_KEY);
const payload = {
card_number: '5531886652142950',
expiry_month: '09',
expiry_year: '32',
cvv: '564',
currency: 'NGN',
amount: '7500',
email: 'developers@flutterwavego.com',
fullname: 'Flutterwave Developers',
phone_number: '+2349012345678',
tx_ref: 'UNIQUE_TRANSACTION_REFERENCE',
redirect_url: 'https://example_company.com/success',
enckey: process.env.FLW_ENCRYPTION_KEY
"authorization": {
"mode": "pin",
"pin": "3310"
}
}
flw.Charge.card(payload)
.then(response => console.log(response));
Validate the Charge
After the encryption and sending the new payload, you'll get one of these responses:
- OTP Required: This response tells you that the customer needs to complete the charge by inputting the OTP sent to their mobile number.
{
"status": "success",
"message": "Charge initiated",
"data": {
"id": 288192886,
"tx_ref": "UNIQUE_TRANSACTION_REFERENCE",
"flw_ref": "FLEG8147171639979534513071",
"device_fingerprint": "N/A",
"amount": 7500,
"charged_amount": 7500,
"app_fee": 105,
"merchant_fee": 0,
"processor_response": "Kindly enter the OTP sent to *******0328",
"auth_model": "PIN",
"currency": "NGN",
"ip": "N/A",
"narration": "CARD Transaction ",
"status": "pending",
"auth_url": "N/A",
"payment_type": "card",
"fraud_status": "ok",
"charge_type": "normal",
"created_at": "2021-07-15T14:06:55.000Z",
"account_id": 17321,
"customer": {
"id": 370672,
"phone_number": "2349012345678",
"name": "Flutterwave Developers",
"email": "developers@flutterwavego.com",
"created_at": "2021-07-15T14:06:55.000Z"
},
"card": {
"first_6digits": "553188",
"last_4digits": "2950",
"issuer": "MASTERCARD CREDIT",
"country": "NG",
"type": "MASTERCARD",
"expiry": "09/32"
}
},
"meta": {
"authorization": {
"mode": "otp",
"endpoint": "/v3/validate-charge"
}
}
}
You can validate the charge as shown below:
const response = await flw.Charge.validate({
otp: req.body.otp,
flw_ref: req.session.flw_ref,
});
- Redirect Required: This response requires the customers to go to the redirected URL to complete the charge.
{
"status": "success",
"message": "Charge initiated",
"data": {
"id": 1254647,
"tx_ref": "UNIQUE_TRANSACTION_REFERENCE",
"flw_ref": "IUSE9942171639769110812191",
"device_fingerprint": "N/A",
"amount": 7500,
"charged_amount": 7500,
"app_fee": 105,
"merchant_fee": 0,
"processor_response": "Pending redirect to issuer's 3DS authentication page",
"auth_model": "VBVSECURECODE",
"currency": "NGN",
"ip": "N/A",
"narration": "CARD Transaction ",
"status": "pending",
"payment_type": "card",
"fraud_status": "ok",
"charge_type": "normal",
"created_at": "2021-07-15T14:06:55.000Z",
"account_id": 17321,
"customer": {
"id": 370672,
"phone_number": "2349012345678",
"name": "Flutterwave Developers",
"email": "developers@flutterwavego.com",
"created_at": "2021-07-15T14:06:55.000Z"
},
"card": {
"first_6digits": "543889",
"last_4digits": "0229",
"issuer": "MASTERCARD MASHREQ BANK CREDITSTANDARD",
"country": "EG",
"type": "MASTERCARD",
"expiry": "10/31"
}
},
"meta": {
"authorization": {
"mode": "redirect",
"redirect": "https://auth.coreflutterwaveprod.com/transaction?reference=IUSE9942171639769110812191"
}
}
}
Verify the Payment
The last step is to verify that the payment was successful before giving value to your customer by querying the verify endpoint.
curl --request GET \
--url https://api.flutterwave.com/v3/transactions/{transaction_ID}/verify \
--header 'Authorization: Bearer FLW_SECRET_KEY' \
--header 'content-type: application/json'
Challenges with v3 Card Payment
While the v3 API was carefully designed to make card payments seamless, we’ve noticed challenges based on our conversations and the feedback we’ve gathered.
Like any product that serves users, it must evolve to meet their needs. We continuously test our product and collaborate with customers to identify areas for improvement. Here are the setbacks from v3:
Redundant Data Transmission and Encryption Overhead
Each time you call the charge endpoint, you have to send the full payload (including the card details), which must be encrypted. This increases computational overhead and introduces unnecessary complexity, especially when dealing with large transactions.
Security Implication
Even though encryption is in place, transmitting sensitive cardholder data multiple times (initiate and authorize charge step) increases the attack surface.
Higher Latency and Network Traffic
Resending the entire request rather than referencing a previously created charge increases network usage and processing time. If multiple users perform transactions simultaneously, it could slow down the system response times and reduce efficiency.
Developer Experience
You need additional logic to determine whether you're initiating or authorizing a charge. Since both actions use the same endpoint, you must check the response, modify the request, and resend it with authorization details while maintaining data integrity. This adds unnecessary complexity compared to a two-step process with separate endpoints.
Developer Onboarding
In v3, our API is only accessible to businesses. You can't create a dedicated developer sandbox environment to experiment with our APIs and simulate your development experience. Many potential customers found this challenging.
How v4 API Improves Card Payment
With v4, we've listened to our customers and redesigned our API to address these pain points. Here are some of the improvements:
OAuth2.0 Secure
Managing test and production API keys in your codebase is no longer necessary. Flutterwave now uses Open Authorization (OAuth2.0), a secure authorization mechanism that connects your application to our servers without exposing static API keys. Unlike API keys, which can be easily exploited if leaked, OAuth2.0 uses access tokens with expiration times, making it much harder for unauthorized users to maintain long-term access.
Dedicated Sandbox Environment
In v4, you can easily onboard as a developer, test our APIs, and simulate your payment gateway needs. The sandbox includes a redesigned UI, a consistent workflow, and a smoother experience as you build and test. Don’t have an account yet? Create one now.
Improved Workflow
Our v4 APIs follow true RESTful principles. Integration is predictable and scalable and follows industry best practices. For example, when initiating a card payment, you no longer need to encrypt the entire payload. Only the card information needs encryption. You also do not need to call the charge card endpoint multiple times to determine the appropriate authorization method.
Better Developer Experience
A major issue with the v3 API was its generic error messages, which did not clearly indicate what went wrong or how to resolve it. In v4, error responses are well-structured and provide clear insights:
{
"status": "failed",
"error": {
"type": "REQUEST_NOT_VALID",
"code": "10400",
"message": "Invalid card number",
"validation_errors": []
}
}
v4 also supports more test cases via scenario keys. This mechanism allows you to simulate different payment scenarios with ease.
Scalability
API requests in v4 follow a consistent flow across all payment methods. This reduces technical overhead. You can create reusable helper functions across your codebase, making integrations more efficient and scalable.
Now that we understand the improvements that come with v4, let's see it in practice.
How to Charge Card Payments in v4
Before we dive into the implementation details, it's important to understand the key change in how to charge a card. You can now choose from the following methods:
- General Flow: This approach breaks the payment process into separate steps, such as setting up the payment method, adding customer details, and handling charge authorization. It gives you more control and allows you to customize the payment experience to fit your needs.
- Orchestrator Flow: A straightforward approach where you initiate a payment, handle the response, and set up the required entities, such as the payment method and customer, in a single flow.
How to Charge Card Payments with the General Flow
Our v4 APIs are secured with OAuth2.0 by default and require a token to access them for a specific period. To generate a token, log into your dashboard to obtain your Client ID and Client Secret. These are needed to generate the token and refresh it once it expires.
curl -X POST 'https://idp.flutterwave.com/realms/flutterwave/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={{CLIENT_ID}}' \
--data-urlencode 'client_secret={{CLIENT_SECRET}}' \
--data-urlencode 'grant_type=client_credentials'
Check out the authentication process to learn more.
Once the token is generated, you can use it to charge a card by following the steps below:
Step 1: Create a Customer
To create a customer, send a request to the create customer endpoint with the customer’s details. Only the customer’s email is required; however, we recommend collecting as much information as possible.
curl --request POST \
--url 'https://developersandbox-api.flutterwave.com/customers' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"address":{
"city":"Gotham",
"country":"US",
"line1":"221B Baker Street",
"line2":"",
"postal_code":"94105",
"state":"Colorado"
},
"name":{
"first":"King",
"middle":"Leo",
"last":"James"
},
"phone":{
"country_code":"1",
"number":"6313958745"
},
"email":"james@example.com"
}'
You'll receive a response containing the customer ID, which you can use for future charges.
{
"status": "success",
"message": "Customer created",
"data": {
"id": "cus_X0yJv3ZMpL",
"address": {
"city": "Gotham",
"country": "US",
"line1": "221B Baker Street",
"line2": "",
"postal_code": "94105",
"state": "Colorado"
},
"email": "james@example.com",
"name": {
"first": "King",
"middle": "Leo",
"last": "James"
},
"phone": {
"country_code": "1",
"number": "6313958745"
},
"meta": {},
"created_datetime": "2025-01-29T12:44:53.049Z"
}
}
Step 2: Create the Card Payment Method
Next, collect the customer’s card details and send a request to the create a payment method endpoint. You must also encrypt card details before sending the requests.
curl --request POST \
--url 'https://developersandbox-api.flutterwave.com/payment-methods' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"type": "card",
"card": {
"encrypted_card_number": "{{$encrypted_card_number}}",
"encrypted_expiry_month": "{{$encrypted_expiry_month}}",
"encrypted_expiry_year": "{{$encrypted_expiry_year}}",
"encrypted_cvv": "{{$encrypted_cvv}}",
"nonce": "{{$randomly_generated_nonce}}"
}
}'
Note that v4 reduces encryption overhead because you only need to encrypt specific parts of the payload, such as the card number, expiry month, expiry year, and CVV, rather than the entire request.
Similar to the customer creation step, you’ll get a payment method ID.
{
"status": "success",
"message": "Payment method created",
"data": {
"type": "card",
"card": {
"expiry_month": 8,
"expiry_year": 32,
"first6": "123412",
"last4": "2222",
"network": "mastercard"
},
"id": "pmd_wlVhaYmkl2",
"meta": {},
"created_datetime": "2024-12-03T14:29:26.650973145Z"
}
}
Step 3: Putting it Together Create the Charge
To initiate the charge, use the customer and payment method IDs you got from the previous steps to send a request to the card charge endpoint. You’ll need to pass in the amount, currency, and a unique reference. Check out the API reference to see other supported parameters.
curl --request POST \
--url 'https://developersandbox-api.flutterwave.com/charges' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"reference": "cedfa85a-a803-4a06-a586-0f81fb9b9f22",
"currency": "USD",
"customer_id": "cus_IpH7CKCUtD",
"payment_method_id": "pmd_wlVhaYmkl2",
"redirect_url":"https://google.com",
"amount": 250,
"meta":{
"person_name": "King James",
"role": "Developer"
}
}
'
Step 4: Authorize the Charge
After initiating the charge, the customer needs to authenticate the transaction. Card authentication varies, but we send a next_action object in create the charge step to indicate the required authentication method.
Similar to v3, card authorization can be any of the following:
- 3DS/VBVSECURECODE
- External 3DS
- Address Verification (AVS)
- PIN
- USSD
For example, AVS requires the customer to provide their address information to authorize the charge.
"next_action": {
"type": "requires_additional_fields",
"requires_additional_fields":{
"fields":[
"authorization.avs.address.postal_code",
"authorization.avs.address.line1",
"authorization.avs.address.state",
"authorization.avs.address.country",
"authorization.avs.address.city"
]
}
},
Possible responses you should cater to include:
| Authorization Method | Response Type |
|---|---|
| 3DS/VBVSECURECODE | redirect_url |
| External 3DS | redirect_url |
| AVS | requires_additional_fields |
| PIN | requires_pin |
| USSD | payment_instructions |
To authorize the charge using AVS, update the charge by sending a request to the update charge endpoint with the required address information and charge ID.
curl --request PUT 'https://developersandbox-api.flutterwave.com/charges/{id}' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"authorization": {
"type": "avs",
"avs": {
"city":"Gotham",
"country":"US",
"line1":"221B Baker Street",
"line2":"",
"postal_code":"94105",
"state":"Colorado"
}
}
}'
Step 5: Verify the Transaction
Finally, you need to verify the transaction details, such as status and amount, before providing value to the customer. You can verify the transaction using either of the following methods:
- Webhook (Recommended): We'll send a webhook with the transaction status if you have webhooks enabled on your dashboard.
{
"webhook_id": "wbk_yXvsB4LzWSwhUCpAPCBR",
"timestamp": 1739456704200,
"type": "charge.completed",
"data": {
"id": "chg_zam88NgLb7",
"amount": 2000,
"currency": "NGN",
"customer": {
"id": "cus_dc0FUyBpd0",
"address": {
"city": "Gotham",
"country": "US",
"line1": "221B Baker Street",
"line2": "",
"postal_code": "94105",
"state": "Colorado"
},
"email": "james@example.com",
"name": {
"first": "King",
"middle": "Leo",
"last": "James"
},
"phone": {
"country_code": "1",
"number": "6313958745"
},
"meta": {},
"created_datetime": "2024-12-25T20:16:38.246Z"
},
"description": null,
"meta": {},
"payment_method": {
"type": "card",
"card": {
"expiry_month": 9,
"expiry_year": 32,
"first6": "553188",
"last4": "2950",
"network": "MASTERCARD",
"billing_address": null,
"cof": null,
"card_holder_name": null
},
"id": "pmd_ujxuBcf4cJ",
"customer_id": null,
"meta": {},
"device_fingerprint": null,
"client_ip": null,
"created_datetime": "2025-02-05T14:06:10.344Z"
},
"redirect_url": null,
"reference": "ex61m23ja3feykheoidho8ilrri",
"status": "succeeded",
"processor_response": {
"type": "approved",
"code": "00"
},
"created_datetime": "2025-02-13T14:24:43.133Z"
}
}
- Charge Endpoint: You can manually check the charge status by sending a request to retrieve a charge endpoint at a specified interval.
curl --request GET \
--url 'https://developersandbox-api.flutterwave.com/charges/{id}' \
--header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: <YOUR_UNIQUE_TRACE_ID>' \
--header 'X-Idempotency-Key: <YOUR_UNIQUE_INDEMPOTENCY_KEY>' \
You’ll get a response similar to this:
{
"status": "success",
"message": "Charge updated",
"data": {
"id": "chg_zam88NgLb7",
"amount": 2000,
"currency": "NGN",
"customer": "cus_EFE4TQhBSf",
"meta": {},
"payment_method_details": {
"type": "card",
"card": {
"expiry_month": 8,
"expiry_year": 2024,
"first6": "123412",
"last4": "4444",
"network": "mastercard"
},
"id": "pmd_NkWibrRJIy",
"customer": "cus_dc0FUyBpd0",
"meta": {}
},
"redirect_url": null,
"reference": "ex61m23ja3feykheoidho8ilrri",
"status": "succeeded",
"processor_response": {
"type": "approved",
"code": "00"
}
}
}
How to Charge Card Payments with the Orchestrator Flow
Charging with the Orchestrator Flow is similar to the General Flow when it comes to creating, authorizing, and verifying a charge. The key difference is that you can initiate the charge directly, without first breaking the process into separate steps for creating a customer and a payment method. To do this, send a request to the orchestrator endpoint.
curl --request POST \
--url 'https://developersandbox-api.flutterwave.com/orchestration/direct-charges' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"amount": 1234.56,
"currency": "USD",
"reference": "YOUR_EXAMPLE_REFERENCE",
"payment_method": {
"type": "card",
"card": {
"encrypted_card_number": "{{$encrypted_card_number}}",
"encrypted_expiry_month": "{{$encrypted_expiry_month}}",
"encrypted_expiry_year": "{{$encrypted_expiry_year}}",
"encrypted_cvv": "{{$encrypted_cvv}}",
"nonce": "{{$randomly_generated_nonce}}"
}
},
"redirect_url": "https://google.com",
"customer": {
"address": {
"country": "US",
"city": "Gotham",
"state": "Colorado",
"postal_code": "94105",
"line1": "221B Baker Street"
},
"phone": {
"country_code": "41",
"number": "7069423351"
},
"name": {
"first": "King",
"middle": "Leo",
"last": "James"
},
"email": "james@example.com"
}
}'
A key parameter to note is the payment_method. This is where you specify the type of payment (in this case, card) and provide the required details that correspond to the selected payment type.
General Flow vs. Orchestrator Flow: Which One Should You Use?
Both flows allow you to charge a customer’s card. As a rule of thumb:
- Use the General Flow for recurring payments, such as subscriptions, where you need to store customer details for future charges.
- Use the Orchestrator Flow for one-time payments where storing customer details is not required.
Use Case: Subscription-Based Service
If you run an on-demand video streaming platform like Netflix that offers monthly or yearly subscriptions and requires recurring billing, the General Flow is the best option. You can securely create and store the customer and payment method during the first charge. For subsequent renewals, you only need the customer_id and payment_method_id to process the payment.
In v4, there are two ways to charge a customer’s card for subscription-based payments:
- Tokenization: This involves replacing the customer’s sensitive card details with a unique token that can be referenced in the future.
curl --request POST \
--url 'https://developersandbox-api.flutterwave.com/charges' \
--header 'Authorization: Bearer {{YOUR_ACCESS_TOKEN}}' \
--header 'Content-Type: application/json' \
--header 'X-Trace-Id: {{YOUR_UNIQUE_TRACE_ID}}' \
--header 'X-Idempotency-Key: {{YOUR_UNIQUE_INDEMPOTENCY_KEY}}' \
--data '{
"reference": "cedfa85a-a803-4a06-a586-0f81fb9b9f22",
"currency": "USD",
"customer_id": "cus_IpH7CKCUtD",
"payment_method_id": "pmd_TusjN23anB",
"recurring":true,
"redirect_url":"https://google.com",
"amount": 250
}
'
Key parameters to note in the requests are:
reference: A unique identifier that links to the card details.
customer_id: A reference to the customer.
payment_method_id: A reference to the payment method.
recurring: A flag that tells Flutterwave the charge is subscription-based.
-
Credential-on-File: This works similarly to tokenization but offers more flexibility. Instead of linking the token strictly to Flutterwave’s platform, this method generates a unique token that can be used across multiple platforms, even if Flutterwave didn’t process the original token creation.
Think of it like a national identity card that allows you to sign up for any banking application without needing to provide your details again.
Use Case: Online Event Ticket Purchase
If you sell tickets for concerts or sporting events like Ticketmaster or Eventbrite, where users make one-time payments, then Orchestrator Flow is the better fit. Since customer details don’t need to be stored for future transactions, this approach keeps the process simple and efficient.
Wrapping Up
The v4 API is a significant upgrade over v3, offering a better developer experience, OAuth 2.0 security, a dedicated sandbox environment, and more. Many of the workarounds required in v3 are no longer necessary, as v4 introduces a clear and concise flow that makes it easier to build scalable payment systems.
To get started:
- Sign up for the new sandbox environment.
- Use the Flutterwave AI Assistant to explore the API, generate sample requests, and troubleshoot common issues.
Top comments (0)