provider: "kernel") collects the user’s card through a card_enrollment action. by default, action.url opens a KERNEL-hosted page on vault.kernel.sh. to keep card entry inside your own application, render @onkernel/vault-react’s KernelCardCapture component on your page and style it to match your brand.
card number, expiry, and cvc are entered in very good security (VGS) iframes, and VGS creates the card in its vault directly from the cardholder’s browser. your page, your servers, and KERNEL never receive the card number. KERNEL receives only the card’s vault id and the cardholder’s email, then enrolls the card for network tokens.
use the embedded component when:
- you want card entry on your own domain, with your own layout, copy, and fonts
- you don’t want to send cardholders to a KERNEL-hosted page during onboarding
action.url instead when a hosted page is acceptable. it needs no frontend work.
card enrollment and per-purchase CVC
collection are embeddable.
alias-mode purchases on any card network require fresh CVC collection, either
embedded or through the hosted fallback. Visa network-token authentication
still uses the KERNEL-hosted
spend_approval page with its own iframe and
passkey window. Network-token Mastercard purchases don’t need that hosted
approval step.Install
Create the wallet on your backend
create the wallet from your authenticated backend, then readaction.capture_token from the card_enrollment action. the token is a secret capability for this one wallet, not an api key.
capture_token is present only on KERNEL wallets. don’t parse it out of action.url; the url format isn’t part of the api.
the wallet starts in pending_authorization. after the cardholder adds a card, it becomes connected.
Render the component
deliver the token to the intended cardholder’s page through your authenticated application, then renderKernelCardCapture:
AddCard.tsx
the component calls the api directly from the cardholder’s browser, with the token as a bearer and no cookies. call it directly rather than through your own proxy: the api rate-limits this route per client address, so every cardholder behind a proxy shares the proxy’s limit.
Style the component
the package ships no css. you style two layers separately.Surrounding form
the component renders stable class hooks. target them under yourclassName:
acme-card.css
card-field container, so give that container an explicit height.
Card fields
css on your page can’t reach inside the VGS iframes. passfieldCss instead; it’s applied to the inputs in all three iframes:
fieldCss supports nested pseudo-classes, @font-face, media queries, and the state classes &.invalid, &.valid, &.empty, &.dirty, and &.touched. the component reads it once, when it mounts; remount the component to change it.
Text
override any of these keys throughlabels: title, description, completeTitle, completeDescription, number, expiry, expirationPlaceholder, cvc, email, emailHint, submit, submitting, retry, checkAgain, and missingToken.
set at least title, description, completeTitle, and completeDescription. the defaults are KERNEL’s lowercase copy, and the default completion text mentions KERNEL. error messages are fixed and can’t be overridden; use onError if you want to show your own.
Allow the component in your CSP
the component loads VGS’s collect script fromhttps://js.verygoodvault.com, renders its iframes, and calls the KERNEL api. merge these directives into your existing content security policy:
fieldCss uses @font-face, also allow the font’s source. you don’t need to allow VGS’s analytics endpoint; blocking it doesn’t affect card capture.
Handle completion
onComplete means KERNEL confirmed the card was added. it isn’t a payment notification. confirm the wallet’s state from your backend before you treat it as ready:
connected wallet has a stored card. inspect the wallet’s payment_methods before creating a purchase.
Handle errors
onError receives one of these codes. the component never surfaces raw api or VGS messages.
after
expired, unavailable, or unconfirmed, the component removes the form.
Token lifetime
acapture_token lasts 30 minutes. when it expires, retrieve the wallet again from your backend; KERNEL returns a new card_enrollment action with a new capture_token. changing the component’s token prop resets it.
if the cardholder leaves the page after creating a card but before KERNEL confirms it, the component makes one best-effort attempt to resend the card as it unmounts or the page unloads. it ignores that request’s result, so the card can still go unrecorded. always confirm the wallet’s state from your backend, as described in handle completion.
Security
- treat
capture_tokenas a secret. deliver it only to the intended cardholder, and never put it in a path, query string, cookie, browser storage, logs, traces, or analytics. if you put it in a link, use a url fragment and clear it once capture completes. - don’t add native card inputs, card-data callbacks, analytics, or session replay around the component.
- serve the page over HTTPS.