provider: "kernel") require a fresh CVC for each purchase, on any card network. Authorization returns pending_authorization with a spend_approval action. Render @onkernel/vault-react’s KernelCardCVC component to keep this step inside your application, or open action.url for the hosted fallback.
The cardholder enters the code in a Very Good Security (VGS) iframe. Your page, your servers, and KERNEL never receive the raw CVC. VGS sends KERNEL a temporary alias bound to this purchase. The component doesn’t collect a card number, enroll a wallet, or submit merchant checkout.
Use this component only for the CVC action whose URL points to
/card-cvc on
your configured KERNEL vault origin. Other spend approvals, including Visa
network-token authentication, still use the hosted URL. Don’t select a CVC
flow by action name or card network alone. Use embedded card
capture for enrollment.Install
Deliver the capability from your backend
After authorizing the purchase, retrieve it from your authenticated backend. There isn’t a dedicatedaction.cvc_token field yet. The fragment extraction below, including the token parameter name and validation regex, is provisional and will be replaced by a dedicated API field. For this interim CVC flow, extract the token parameter from the action URL’s fragment and deliver it only to the intended cardholder’s authenticated application. Validate the origin and /card-cvc path before selecting this component:
https://vault.kernel.sh when targeting another environment. This fragment extraction is specific to the current CVC integration; it doesn’t change enrollment’s action.capture_token contract. cvcToken is a one-purchase capability, not an API key or enrollment token. Keep the action URL available as a hosted fallback. Don’t send either capability to your automation agent.
Render the component
ConfirmPurchase.tsx
KernelCardCVC requires baseUrl to be a bare origin, unlike KernelCardCapture, which accepts a path prefix. An invalid baseUrl throws a developer error during render, before sending the capability; it doesn’t call onError.
The component reads GET /vault/card-cvc/current directly with the bearer and credentials: "omit". Don’t route reads through your backend: the API rate-limits per client address, so a proxy makes cardholders share its limit. The iframe submits through VGS, not through your page or backend.
Changing token or baseUrl unmounts the old field and resets the component. Don’t change them during submission. An unmounted component ignores late callbacks; retrieve purchase state from your backend if you don’t know whether collection completed.
Style the component
Style the surrounding form through yourclassName. Give the iframe container an explicit height:
Page CSS can’t reach into the iframe. Use
fieldCss for input styling, including nested selectors such as &:focus, &.invalid.touched, &::placeholder, media queries, and @font-face. Supply it before mounting; remount to change it.
Override these labels keys: title, description, completeTitle, completeDescription, cvc, cvcPlaceholder, submit, submitting, loading, retry, and missingToken. Set the title, descriptions, and completion copy to your application’s wording; defaults use KERNEL’s lowercase copy and mention KERNEL. Error messages are fixed.
Allow the component in your CSP
Merge these directives into your existing policy:connect-src. If you use external fonts, allow their source in the appropriate context and test the iframe rendering. The hosted fallback cannot itself be framed.
Handle completion and expiry
onComplete confirms CVC collection, not a merchant payment. Retrieve the purchase from your backend and inspect state.status === "ready" and expires_at before resuming checkout. Fill and submit checkout before expires_at.
The unused collection capability lasts 30 minutes. After capture, the purchase expires at the temporary CVC alias deadline, five minutes by default. Repeated fill or collection doesn’t extend that deadline. An expired alias-mode purchase requires a new purchase and fresh authorization; refreshing an enrollment token won’t recover it.
Submission times out after 60 seconds: the component hides the form, calls onError('unconfirmed'), and ignores late approval callbacks.
If a dispatched submission has an unknown outcome, retrieve the existing purchase before taking any further action. Don’t automatically recollect, create a second purchase, or repeat payment.
Handle errors
The form is removed from use after
expired, unavailable, invalid_response, or unconfirmed. The component doesn’t resend CVC submissions on unmount or unload. A known field validation failure or definitive rate limit permits retry.
Security
- Serve your page over HTTPS with no-store and no-referrer policies.
- Treat the CVC capability as a secret. Never put it in a path, query string, cookie, browser storage, logs, traces, or analytics. If you deliver a link, use a fragment and clear it after completion or terminal invalidation.
- Don’t add native CVC inputs, raw-value callbacks, analytics, or session replay around the component. Control scripts and dependencies that can modify the surrounding page.
- Raw CVC stays in the VGS-hosted field and VGS processing. Your page and KERNEL never receive it. This preserves the isolated-field boundary used by embedded card capture; it doesn’t certify your PCI scope or SAQ eligibility. Confirm your integration’s eligibility and script-security requirements with your acquirer or QSA.
- Don’t configure VGS to accept every integrator origin. The submission origin is
https://js.verygoodvault.com; no VGS credentials or callback secrets belong in your frontend.