Recollect Security Code
Securely recapture CVC codes for saved cards with a simple, efficient tool.To boost authorization rates while adhering to PCI compliance, some Payment Service Providers (PSPs) recommend or mandate that Customer-Initiated Transactions (CITs) with saved cards include the card security code (CSC, also known as CVV or CVC), which cannot be stored in long-term persisted tokens. This guide equips merchants and platforms with the tools to securely recollect the CVC/CVV from customers, enhancing transaction security and meeting PSP requirements. Recollection may be triggered by factors like heightened fraud detection, updated risk policies, card network rules, or regional regulatory changes, ensuring compliance and improved payment success.
Getting Started
To get started, you will need to create a Basis Theory Account and a TEST Tenant.
Public Application
You will need a Public Application for your frontend. Click here to create one using the Basis Theory Customer Portal.
This will create an application with the following Access Controls:
- Permissions:
token:update
Configure Elements SDK
Basis Theory Elements are available for the following technologies. Click below for detailed instructions on how to install and configure them.
Add the CVC Element
Once installed and configured, add the CardVerificationCode
Element to your application. This will enable your users to type in their Card Security Code in your form, while ensuring your systems never come in contact with the data.
- JavaScript
- React
- iOS
- Android
- React Native
<div id="cardVerificationCode" style="width: 100%;"></div>
import { BasisTheory } from '@basis-theory/web-elements';
let bt;
let cardVerificationCodeElement;
async function init() {
bt = await basistheory('<PUBLIC_API_KEY>');
cardVerificationCodeElement = bt.createElement('cardVerificationCode', {
targetId: 'myCardVerification',
cardBrand: 'visa',
});
await cardVerificationCodeElement.mount('#cardVerificationCode');
}
init();
import React, { useRef, useState } from 'react';
import {
BasisTheoryProvider,
CardVerificationCodeElement,
useBasisTheory,
} from '@basis-theory/react-elements';
export default function App() {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Ref to get access to the Element instance
const cardVerificationRef = useRef(null);
return (
<BasisTheoryProvider bt={bt}>
<CardVerificationCodeElement
id="myCardVerification"
ref={cardVerificationRef}
cardBrand="visa"
/>
</BasisTheoryProvider>
);
}
Implementation snippets are coming soon.
Please check our SDKs for examples.
Implementation snippets are coming soon.
Please check our SDKs for examples.
import React, { useRef } from "react";
import { SafeAreaView, ScrollView, StatusBar, StyleSheet, View } from "react-native";
import type { BTRef } from "@basis-theory/react-native-elements";
import { CardVerificationCodeElement, useBasisTheory } from "@basis-theory/react-native-elements";
const App = (): JSX.Element => {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
const cardVerificationCodeRef = useRef<BTRef>(null);
return (
<SafeAreaView>
<StatusBar />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.viewContainer}>
<CardVerificationCodeElement btRef={cardVerificationCodeRef} placeholder="CVC" style={styles.elements} />
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
cardNumber: {
backgroundColor: "#eeeeee",
borderColor: "blue",
borderWidth: 2,
color: "purple",
height: 40,
margin: 12,
padding: 10,
},
viewContainer: {
display: "flex",
flexDirection: "column",
marginTop: 32,
},
});
export default App;
Update the Token
Now we will invoke the Update Token endpoint from the SDK, passing the CardVerificationCode
Element in the payload. This will securely update the card
token by transferring the value from the frontend Element to the Basis Theory API, where the data will be strongly encrypted and temporarily stored in a compliant environment.
Given you had previously saved a Token:
{
"id": "1cd9c8bf-99fd-4784-ba69-68b15b301019",
"tenant_id": "74eca6ab-f94d-49bc-9f3c-6144eb3415ac",
"type": "card",
"card": {
"bin": "42424242",
"brand": "visa",
"last4": "4242",
"expiration_month": 12,
"expiration_year": 2025,
"funding": "credit",
"authentication": "sca_required"
},
"fingerprint": "BKJYqf2tcvhTHSXN7EvBJLviN3PBYRgwoJgce8VAfnSr",
"_extras": {
"deduplicated": false
},
...
}
Add a submit function along with a button to trigger it:
- JavaScript
- React
- iOS
- Android
- React Native
<div id="cardVerificationCode" style="width: 100%;"></div>
<button id="submit">Submit</button>
import { BasisTheory } from '@basis-theory/web-elements';
let bt;
let cardNumberElement;
let cardExpirationDateElement;
let cardVerificationCodeElement;
async function init () {
...
document.getElementById("submit").addEventListener("click", submit);
}
async function submit () {
try {
await bt.tokens.update('1cd9c8bf-99fd-4784-ba69-68b15b301019', {
data: {
cvc: cardVerificationCodeElement,
}
});
// TODO process the card payment
} catch (error) {
console.error(error);
}
}
init();
import React, { useRef, useState } from 'react';
import {
BasisTheoryProvider,
CardVerificationCodeElement,
useBasisTheory,
} from '@basis-theory/react-elements';
export default function App() {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Ref to get access to the Element instance
const cardVerificationRef = useRef(null);
const submit = async () => {
try {
await bt.tokens.update('1cd9c8bf-99fd-4784-ba69-68b15b301019', {
data: {
cvc: cardVerificationRef.current,
}
});
// TODO process the card payment
} catch (error) {
console.error(error);
}
}
return (
<BasisTheoryProvider bt={bt}>
...
<button onClick={submit}>Submit</button>
</BasisTheoryProvider>
);
}
Implementation snippets are coming soon.
Please check our SDKs for examples.
Implementation snippets are coming soon.
Please check our SDKs for examples.
import React, { useRef } from "react";
import { Button, SafeAreaView, ScrollView, StatusBar, StyleSheet, View } from "react-native";
import type { BTRef } from "@basis-theory/basis-theory-react-native";
import { CardVerificationCodeElement, useBasisTheory } from "@basis-theory/react-native-elements";
const App = (): JSX.Element => {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
const cardVerificationCodeRef = useRef<BTRef>(null);
const submit = async () => {
try {
await bt.tokens.update('1cd9c8bf-99fd-4784-ba69-68b15b301019', {
data: {
cvc: cardVerificationRef.current,
}
});
// TODO process the card payment
} catch (error) {
console.error(error);
}
}
return (
<SafeAreaView>
<StatusBar />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.viewContainer}>
<CardVerificationCodeElement btRef={cardVerificationCodeRef} placeholder="CVC" style={styles.elements} />
</View>
<Button onPress={submit} title="Submit" />
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
cardNumber: {
backgroundColor: "#eeeeee",
borderColor: "blue",
borderWidth: 2,
color: "purple",
height: 40,
margin: 12,
padding: 10,
},
viewContainer: {
display: "flex",
flexDirection: "column",
marginTop: 32,
},
});
export default App;
The updated Token stores the cvc
for 24 hours, allowing you to process the new CIT.
Authentication
Once the Token has been created, merchants may need to authenticate the cardholder to comply with PSD2’s Strong Customer Authentication (SCA) requirements and reduce fraud. The specific authentication steps depend on the card’s region, issuer requirements, and the merchant’s risk strategy.
3D Secure
3D Secure (3DS) is the standard protocol for meeting PSD2 SCA requirements in Europe and enhancing fraud prevention globally. It introduces an additional verification step, such as a one-time password (OTP) or biometric authentication. SCA exemptions may apply for certain transactions, such as low-risk or merchant-initiated payments. Implementing 3DS2 ensures compliance while keeping checkout friction minimal.
if (token.card.authentication === 'sca_required') {
// trigger the 3DS authentication flow
}
Next Steps
Now that you've implemented this workflow in your application, the next step is to process payments using the refreshed token.
Click here to visit our Charge a Card guide.