Card Tokenization

Learn how to use your customer’s card to process recurring payments.

Tokenization enables the implementation of recurring payments by securely storing a token that represents the customer's card, which can then be used for future transactions.

🚧

Handling Sensitive Data

You should never save a customer's card details; the details are represented by a token, which is what you save.

Flutterwave offers two authentication models that can be used to process subsequent charges.

  • 3D Secure (3DS) : This model requires customers to authenticate themselves through a challenge, such as a one-time password (OTP), providing an added layer of security for the transaction.By default, subsequent charges use this authentication model.
  • NOAUTH: This model enables a smoother customer experience by bypassing identity verification. Merchants using this model typically have a custom 3DS provider or another method for verifying the customer's identity. By default, bulk subsequent charges require this authentication model to process multiple transactions.

📘

For Single and Bulk Subsequent Charges to be processed via NOAUTH, Kindly request this feature on your account via email

Unlike payment plans, you are responsible for managing the customer's subscription yourself—cancellation, reactivation, and charging them are all your responsibility.

To implement a recurring charge, first, you'll need to charge the customer normally, for instance, via direct charge or Flutterwave Inline . Make sure to allow payments only via card, as only cards can be tokenized.

When the payment is made, you can verify the payment as usual. In the verification response, you'll find a token field in the data.card object. This is the token representing the card.

🚧

Token Expiry

Customer card tokens are valid for one year only. To avoid transaction errors caused by expired tokens, it is important to re-tokenize the card before the existing token expires.

{
  "status": "success",
  "message": "Transaction fetched successfully",
  "data": {
    "status": "successful",
    "payment_type": "card",
    //...
    "card": {
      "first_6digits": "455605",
      "last_4digits": "2643",
      "issuer": "MASTERCARD GUARANTY TRUST BANK Mastercard Naira Debit Card",
      "country": "NG",
      "type": "MASTERCARD",
+     "token": "flw-t1nf-93da56b24f8ee332304cd2eea40a1fc4-m03k",
      "expiry": "01/23"
    },
    "customer": {
      "email": "[email protected]",
      // ...
    }
  }
}

You'll need to store this token (along with the customer's email you provided). To charge the card again in the future, pass the token and the email to charge as a payload to the Create tokenized charge endpoint.

🚧

Tokens are Tied to Email Addresses

The token is tied to the email address you specified on the first charge. This means that if a customer changes their email address on your app, you'll need to update the token details for future charges to work.

// Install with: 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 details = {
	token: user.card_token,
	currency: 'NGN',
	country: 'NG',
	amount: 24000,
	email: user.email,
	tx_ref: this.generateTransactionReference(),
	narration: 'Payment for monthly magazine subscription',
};
await flw.Tokenized.charge(details);
// Install with: composer require flutterwavedev/flutterwave-v3

$flw = new \Flutterwave\Rave(getenv('FLW_SECRET_KEY')); // Set `PUBLIC_KEY` as an environment variable
$tokenizedChargeService = new \Flutterwave\TokenizedCharge();
$details = [
    "token" => $user->card_token,
    "currency" => "NGN",
    "country" => "NG",
    "amount" => 24000,
    "email" => $user->email,
    "tx_ref" => $this->generateTransactionReference(),
    "narration" => "Payment for monthly magazine subscription",
];
$response = $tokenizedChargeService->tokenCharge($details);
# Install with: gem install flutterwave_sdk

require 'flutterwave_sdk'

flw = Flutterwave.new(ENV["FLW_PUBLIC_KEY"], ENV["FLW_SECRET_KEY"], ENV["FLW_ENCRYPTION_KEY"])
charge = TokenizedCharge.new(flw)
details = {
    token: user.card_token,
    currency: "NGN",
    country: "NG",
    amount: 24000,
    email: user.email,
    tx_ref: generate_transaction_reference,
    narration: "Payment for monthly magazine subscription",
}
response = charge.tokenized_charge details
print response
curl --request POST 'https://api.flutterwave.com/v3/tokenized-charges' \
  --header 'Authorization: Bearer YOUR_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
     "token": "flw-t1nf-93da56b24f8ee332304cd2eea40a1fc4-m03k",
     "currency": "NGN",
     "country": "NG",
     "amount": 24000,
     "email": "[email protected]",
     "tx_ref": "8676oi9764823kefth",
     "narration": "Payment for monthly magazine subscription",
}'

Check out our endpoint documentation for details and more options.

You can store the information in the data.card object and use it to provide a better experience for your customers. For example, you could send a reminder when their card is about to expire, or display "MasterCard ending in 2643" in their billing settings, so they can confirm which card will be charged.
You can also charge multiple tokens in one go. See the reference docs for more details.

Processing Subsequent Charges.

By default, subsequent tokenized transactions are processed via 3D Secure (3DS). This means when you try to charge a customer's card via the generated token, the customer would then be required to authenticate with a challenge (e.g., one-time password).

{
    "token": "flw-t1nf-1dd5c21361bb85c64deb7ff57ec891b2-m03k",
    "currency": "NGN",
    "country": "NG",
    "amount": "1500",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "tx_ref": "token_ch_fhfgf435dfcfsdfdSDghdv",
    "ip": null,
    "narration": "Sample tokenized charge",
    "redirect_url": "https://example_company.com/success"
}

A successful response should include the authentication model VBVSECURECODE (3DS) and a redirect_url that directs the customer to the authentication page for verification.

{
	"status": "success",
	"message": "Charge initiated",
	"data": {
		"id": 2534420,
		"tx_ref": "testToken111",
		"flw_ref": "FLW-MOCK-0a6b80654370ff4b0987851ce0e611c0",
		"redirect_url": "https://flutterwave.com/ng",
		"device_fingerprint": "N/A",
		"amount": 12000,
		"charged_amount": 12000,
		"app_fee": 168,
		"merchant_fee": 0,
		"processor_response": "Approved",
		"auth_model": "VBVSECURECODE",
		"currency": "NGN",
		"ip": "pstmn",
		"narration": "test_token_charge",
		"status": "pending",
		"payment_type": "card",
		"created_at": "2021-10-07T17:43:46.000Z",
		"account_id": 20937,
		"customer": {
			"id": 1409822,
			"phone_number": null,
			"name": "John Doe",
			"email": "[email protected]",
			"created_at": "2021-10-07T17:40:57.000Z"
		},
		"card": {
			"first_6digits": "553188",
			"last_4digits": "2950",
			"issuer": "MASTERCARD  CREDIT",
			"country": "NG",
			"type": "MASTERCARD",
			"expiry": "09/32"
		},
		"meta": {
			"authorization": {
				"mode": "redirect",
				"redirect": "https://ravesandboxapi.flutterwave.com/mockvbvpage?ref=FLW-MOCK-0a6b80654370ff4b0987851ce0e611c0&code=00&message=Approved. Successful&receiptno=RN1633628627056"
			}
		}
	}
}

{
	"status": "error",
	"message": "Wrong token or email passed",
	"data": null
}

Bulk Tokenization

📘

This feature requires subsequent charges to be processed via NOAUTH. Kindly request this feature on your account via email

Flutterwave supports tokenizing cards in bulk, using this method, you can add multiple card tokens and save your customers details so they can complete recurring payments with ease.

To add multiple card tokens, you need to send the following information to the bulk tokenize charge endpoint:

  1. Bulk_data: This array contains the card token and customer details to be tokenized.
  2. Retry_strategy: This object informs us on how to treat failed tokenization attempts. You can specify the time interval between each attempt and the number of attempts to make.
{
	"title": "Sample bulk tokenization payment",
	"retry_strategy": {
		"retry_interval": 120,
		"retry_amount_variable": 60,
		"retry_attempt_variable": 2
	},
	"bulk_data": [
		{
			"currency": "NGN",
			"token": "flw-t1nf-f9b3bf384cd30d6fca42b6df9d27bd2f-m03k",
			"country": "NG",
			"amount": 3500,
			"email": "[email protected]",
			"first_name": "Example",
			"last_name": "User",
			"ip": "123.876.0997.9",
			"tx_ref": "akhlm-pstmn-blkchrg-xx6"
		},
		{
			"currency": "NGN",
			"token": "flw-t1nf-f9b3bf384cd30d6fca42b6df9d27bd2f-m03k",
			"country": "NG",
			"amount": 3000,
			"email": "[email protected]",
			"first_name": "Test",
			"last_name": "User",
			"ip": "123.876.0997.9",
			"tx_ref": "akhlm-pstmn-blkchrge-xx7"
		}
	]
}

You'll get a response like this:

{
	"status": "success",
	"message": "Bulk charge successful",
	"data": {
		"id": 130,
		"created_at": "2020-01-19T21:43:39.000Z",
		"approver": "N/A"
	}
}

In our commitment to uphold the service uptime, we enforce specific limitations on your retry attempts. These restrictions come into effect based on the error message received during the card charge. The ensuing rules are then applied accordingly:

S/NError messageRestriction
1.Insufficient funds3 sequential attempts and the subsequent tokenization attempts on the card would be declined for a day. The cycle resets at the end of each day.
2.Do not Honour2 sequential attempts and the subsequent tokenization attempts on the card would be declined for a week. The cycle resets at the end of each week.

After initiating the bulk tokenization, you must confirm the status of the bulk payment before giving value.