Card Tokenization

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

Tokenization allows you to implement recurring payments by saving a token representing the customer's card and using that on subsequent charges.

🚧

Handling Sensitive Data

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

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.

Tokenizing 3DS Cards

When a merchant tries to charge a customer with a card token, the charge is processed as NOAUTH without any need for authentication.

If you choose to enforce 3DS i.e. allow your users to authenticate with a challenge, you should add do_3ds and redirect_url to the card token payload. By setting do_3ds to true, Flutterwave will charge the tokenized charge via VBVSECURECODE (3DS auth).

We will also redirect the user to the data.meta.authorization.redirect to authorize the token charge.

{
    "token": "flw-t1nf-1dd5c21361bb85c64deb7ff57ec891b2-m03k",
    "currency": "NGN",
    "country": "NG",
    "amount": 12000,
    "email": "[email protected]",
    "full_name": "Flutterwave Developers",
    "ip": "pstmn",
    "narration": "test_token_charge",
    "tx_ref": "testToken111",
+    "do_3ds": true,
+    "redirect_url": "https://flutterwave.com/ng",
    "meta": {
        "sub_meta_1": "meta_child_1",
        "sub_meta_2": "meta_child_2"
    }
}

You'll get a response like this:

{
	"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": "Flutterwave Developers",
			"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

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.