Recollect a CVC for a Saved Card
In this guide, we will use Credova Elements SDKs to recollect a CVC for a saved card — attaching a freshly re-entered CVC without asking the customer to re-enter the whole card. This uses the cards.updateCvc() method, available in both the JavaScript and React SDKs.
How it works
- Mount a standalone
CardVerificationCodeElementand have the customer enter their CVC. - Call
publicsquare.cards.updateCvc(cardId, cvcElement). - PublicSquare confirms the card belongs to your account, then the CVC is attached directly from the customer's browser — it never touches your servers or PublicSquare's, so your PCI scope doesn't change.
- The CVC is attached to the card and is ready for the next charge. Call
updateCvc()right before you charge the card.
Before you start
Publishable Key- Loads Credova Elements in the browser. It is safe to put in frontend code.
This guide uses the same Publishable Key as Save Cards. You need the id of a saved card. If you do not have one, save it with Save Cards.
updateCvc() needs version 2.0.0 or later of @publicsquare/elements-js or @publicsquare/elements-react.
Mount the CVC Element
Mount a standalone CardVerificationCodeElement. It is the same element as in Save Cards, on its own, without the rest of the card form.
- JavaScript
- React
<div id="cardVerificationCode"></div>
import { PublicSquare } from '@publicsquare/elements-js';
let publicsquare;
let cvcElement;
async function init() {
publicsquare = await new PublicSquare().init('<PUBLISHABLE_API_KEY>');
cvcElement = publicsquare.createCardVerificationCodeElement({});
cvcElement.mount('#cardVerificationCode');
}
init();
import React, { useRef } from 'react';
import {
PublicSquareProvider,
CardVerificationCodeElement,
} from '@publicsquare/elements-react';
export default function App() {
const cvcRef = useRef(null);
return (
<PublicSquareProvider apiKey={apiKey}>
<CardVerificationCodeElement id="cardVerificationCode" ref={cvcRef} />
</PublicSquareProvider>
);
}
Call updateCvc
Once the customer submits the form, call cards.updateCvc() with the card's id and the mounted CVC element:
- JavaScript
- React
<!-- Form from above -->
<button id="submit">Submit</button>
async function init() {
...
document.getElementById('submit').addEventListener('click', submit);
}
async function submit(cardId) {
const response = await publicsquare.cards.updateCvc(cardId, cvcElement);
if (response.error) {
// handle the error — see "Handle the response" below
return;
}
// proceed to charge the card
}
init();
export default function App() {
const { publicsquare } = usePublicSquare();
const submit = async (cardId) => {
const response = await publicsquare.cards.updateCvc(cardId, cvcRef.current);
if (response.error) {
// handle the error — see "Handle the response" below
return;
}
// proceed to charge the card
};
return (
<PublicSquareProvider apiKey={apiKey}>
...
<button onClick={() => submit(cardId)}>Submit</button>
</PublicSquareProvider>
);
}
Handle the response
updateCvc() resolves rather than throwing, whether the update succeeds or fails — check response.error instead of wrapping the call in try/catch:
{
"id": "card_AjkCFKAYiTsjghXWMzoXFPMxj",
"type": "card",
"created_at": "2024-06-24T13:51:24.980Z",
"modified_at": "2026-09-21T13:51:24.980Z"
}
{
"error": {
"error": "not_found",
"data": { ... }
}
}
A successful response means the CVC was accepted and attached to the card — it says nothing about whether the CVC is actually correct.
When to recollect
The recollected CVC is attached to the card for the next charge. The card does not keep it indefinitely, and there is no expiration event or webhook.
Call updateCvc() immediately before you charge the card. If time passes between the update and the charge, prompt the customer for their CVC again and call updateCvc() a second time. Treat an earlier update as if it never happened rather than relying on it.
A CVC is optional for a saved card. You can save and charge a card without one. See Saving a card without a CVC.
Verification happens at authorization, not at update
updateCvc() response is not an approved card. It only confirms the CVC was attached to the card — the card issuer doesn't check it until you actually charge the card.updateCvc() does not contact the card network. It only attaches the CVC. The CVC is only validated when the next charge on that card goes through Accept Card Payments or Authorize and Capture Payments and reaches the issuer. Just like a first-time card charge, a succeeded payment status doesn't guarantee the CVC matched — read cvv2_reply on the resulting card, or verification.result.card_security_code if you ran a verification, to see whether the issuer confirmed it. See Read the Verification Result for the full set of values that field can return.
Security
The CVC goes directly from the customer's browser to Basis Theory. It never reaches your servers or PublicSquare's, so re-collecting a CVC doesn't change your PCI scope.
Conclusion
You attached a new CVC to a saved card. Charge the card right after the update using Accept Card Payments, and check the resulting cvv2_reply to confirm the issuer accepted it.