Skip to main content
add payments to your existing browser agent without passing card numbers or cvc through your application’s code or model context. connect a wallet once, then verify and approve each purchase before completing checkout.

Before you start

  • have an existing browser agent. this guide adds payment handling, not navigation or reasoning.
  • choose a wallet integration from the wallet overview, then follow its tab below. for shop pay, follow the shop pay guide, which uses the same controller pattern.
  • install a KERNEL sdk with the vaults resource. set KERNEL_API_KEY and KERNEL_PROJECT_ID in your controller.
  • use a low-value checkout you control. paying with the user’s own card is live-only, and fill writes only on the origin of the purchase’s merchant_url, so you need the top-level checkout page’s url and verified field selectors for the card inputs. link is live-only and requires an https merchant origin. on stripe checkouts that support link pay tokens, KERNEL fills the payment without field selectors; elsewhere you need verified field selectors for the virtual card. agentcard requires a native processor adapter; the processor doesn’t need to be stripe.
  • for agentcard, set AGENTCARD_MODE in your controller and verify it against the credential’s mode. customer-owned configs expose test_mode (true means sandbox); for KERNEL-managed credentials, confirm the deployment’s mode. stop if the mode is unknown or mismatched.
  • identify how you’ll read the merchant’s trusted order record. you need it to confirm a matching paid order. deterministic checkout data can verify purchase details before submission, but without the order record afterward, the result remains indeterminate.
use KERNEL-managed credentials by default. optional client setup belongs in your controller: see link or agentcard.

Roles and resources

  • controller: your trusted application code. it calls KERNEL, verifies purchases, authorizes field bindings, presents user actions, and observes payment state.
  • agent: your browser automation. it proposes purchase details and selectors, then completes the approved checkout.
  • user: the person who connects a payment method, confirms the purchase, and completes provider approval.
a vault groups KERNEL items. a wallet item represents a provider connection; a card item references that wallet in the same vault and tracks payment input and authorization state. neither item is the user’s underlying wallet or card.

Shared safety rules

  • keep wallet enrollment and provider approval outside the agent and its browser. never put action urls, oauth codes, provider responses, api keys, or browser connection urls in model context.
  • independently verify purchase details in your controller before creating, updating, or authorizing a card item. user confirmation alone doesn’t validate an agent’s proposal.
  • submit checkout once through the merchant’s normal form. don’t retry submission or fall back from fill to aliases after failure or uncertainty. fill never submits, so a retry is safe. retry only after checking the page, and never in an automatic loop.
  • report success only after the merchant’s trusted order record confirms the matching paid order. a timeout, missing event, or browser deletion doesn’t cancel a payment.

One-time setup

1. Create a vault

scope the client and vault to the project that will own the browser session. these clients disable automatic sdk retries.
vaults.upsert creates the vault or retrieves one with the same name. vault names are immutable within the project.

2. Connect a wallet

allow at most one wallet item per provider in a vault. list the vault’s items and group wallets by spec.provider before rendering your payment settings: recheck in your controller immediately before creating a wallet. the api makes item keys unique, not providers, so a different key can create a duplicate wallet. deleting a wallet invalidates its dependent card items; use an explicit remove-and-replace flow instead of adding a second wallet.
  1. let the user select a provider that doesn’t already have a wallet in the vault.
  2. create the wallet item through your controller, following the pay with card setup, link setup, or agentcard setup.
  3. present the returned action using the authenticated flow below. the user connects or enrolls their real payment method with the provider.
  4. wait for the wallet’s status to become connected before preparing a purchase.

Present hosted actions in your application

provider action urls are bearer-like handoffs to enrollment or approval. route them through your controller:
  1. your controller retrieves the item and keeps the raw action url out of logs, analytics, and model context.
  2. store the action server-side under an opaque id bound to the authenticated user, vault id, item key, and action name.
  3. render a link to your own authenticated action endpoint. before redirecting, verify the session owns that binding and the item still returns the same action.
  4. send the redirect with Cache-Control: no-store and Referrer-Policy: no-referrer.
  5. apply a short application ttl capped by item.expires_at or state.authorization.expires_at when present. invalidate the record immediately when the action changes, disappears, or reaches a terminal state.
the presentProviderAction functions later in this guide represent this application-owned flow. the checkout agent and its browser must never receive the raw provider url.

For each purchase

1. Attach the vault to a browser

vault attachments are fixed at browser creation. use the same project-scoped client that created the vault.
the examples create a headful browser. to run checkout headless, create the browser with at least 2GiB of memory (memory: "2GiB", or --memory 2GiB in the cli). heavy checkout pages can exhaust a 1GiB headless browser, which then stops responding to KERNEL during authorization and fill.
browser_live_view_url lets the user watch the checkout during confirmation and agentcard approval pauses. presentLiveView represents your authenticated user-facing page: keep the url server-side with the user and browser session binding, render or embed it only after checking that session, and remove it when you delete or time out the browser. don’t log the url or put it in model context. see live view for iframe and csp requirements. connect your existing agent to browser.cdp_ws_url. see Controlling a Browser for supported connection options. navigate to checkout in this session before verifying the purchase. use the same session to inspect and submit it; the vault attachment includes items created later.

2. Verify and confirm the purchase

  1. let the agent propose the merchant, amount, currency, and item or cart contents. treat every proposed value as untrusted.
  2. independently obtain the expected values from a trusted source. prefer your order or cart backend. when no backend exists, use deterministic page extraction with fixed selectors or structured page data, not another model response.
  3. normalize the values in your controller and compare the proposal with the trusted result. compare the amount in minor currency units and require the merchant, currency, and item or cart contents to match.
  4. stop when any value is missing, cannot be verified, or disagrees. do not create or update a card item and do not invoke authorization.
  5. show the independently verified values to the user and wait for explicit confirmation.
  6. freeze that verified, confirmed purchase object. derive the card specification and any authorization request from that same object. do not accept replacement values from the agent after confirmation.
for stripe payment links, see checkout-specific notes for structured response fields and adaptive pricing.

3. Collect other checkout fields

collect required email, billing, shipping, phone, and other customer fields from the user or their previously approved backend data. pass them separately from payment input; don’t ask the agent to invent missing values. answer any agent disclosure truthfully in the merchant’s form and verify the control is selected before submission. if a required field or disclosure can’t be completed and verified, stop. see checkout-specific notes for stripe’s disclosure controls.

4. Prepare payment input and submit once

follow the tab for your provider. each path uses the frozen purchase object from step 2, a connected wallet in the same vault, and this browser session.

Create and authorize the purchase

a purchase using the user’s own card is approved before checkout, so authorize takes no browser or page parameters. authorize once the agent reaches the final checkout page: the one-time security code expires shortly after it’s issued.
  1. create a card item named notebook-order from the verified purchase. set merchant_url to the top-level checkout page’s url. fill writes only on that url’s exact origin, so a checkout hosted on another domain needs that domain’s url. visa cards also require merchant_country. card items with provider: "kernel" can’t be updated; to change the purchase, delete the item and create a new one.
  2. require authorize in available_operations and invoke it, then present any returned spend_approval action through your controller. visa cards use it for the cardholder’s approval, and cards without network tokens use it to collect a fresh security code. supported mastercard cards return no action.
  3. wait for the card to become ready. a wait read holds for at most 60 seconds, so keep retrieving while it’s pending_authorization; the cardholder has up to 30 minutes to use the approval link.
run the cli’s --open only in your controller or a human-operated terminal, and keep its output outside the agent. repeat the get while state.status is pending_authorization.declined means the card network refused to issue a code. stop; KERNEL never approves the purchase again on its own, so the cardholder must approve a new purchase. for recovery_required, stop and follow verify the outcome.

Fill the card

for eligible cards, fill writes a network token number, its expiry, and a one-time security code. checkoutURL / checkout_url is the browser’s exact current top-level https url, including query and fragment, on the origin of merchant_url. a page on another origin returns 403 with destination_denied before any writes. payment inputs inside processor iframes are supported.cards collected through KERNEL have no stored billing details. requesting a billing_* field returns field_unavailable before any writes, so enter billing details from the user’s approved data instead.
for separate month and year inputs, bind exp_month (MM) and exp_year (YYYY) instead of expiration. request only fields that are currently visible. if a completed fill reveals another field, make a separate fill with only the new field.handle the per-field outcomes as in the fill outcome contract: fill never submits, so a retry is safe. retry only after checking the page, and never in an automatic loop.only continue on completed. complete the remaining customer fields and disclosures, then submit once, promptly: the one-time security code expires. verify the outcome against the merchant’s order record.

Report the merchant outcome

after the merchant’s order record shows a definitive outcome, report it once with confirm_transaction when the card advertises it. report the amount the merchant charged, in minor units, its currency as an uppercase code such as USD, and the time you observed the outcome. don’t report an outcome you couldn’t verify, and don’t repeat a report whose response was lost. waitForMerchantResolution represents your order backend.
a report records the outcome you observed. it doesn’t prove that payment succeeded and isn’t a substitute for the merchant’s order record.

Verify the outcome

use the merchant’s trusted order record to confirm a paid order whose merchant, amount, currency, and items match the frozen purchase. item state, events, and the checkout page provide supporting evidence, not proof by themselves. if the record is unavailable or the sources disagree, keep the result indeterminate and don’t retry. retain the vault id, card key, browser id, and last event id until reconciliation is complete. delete the browser after outcome inspection or your reconciliation deadline; this doesn’t undo provider execution or cancel an order. keep or delete the vault and provider items based on future use, except when recovery_required prohibits deletion.

Checkout-specific notes

stripe can render hidden or duplicate copies of its disclosure control for responsive layouts. target the visible label. if the label doesn’t toggle the control, locate the associated real input[type="checkbox"] and invoke its native dom click(). read that same input’s checked property and require it to be true before submission. if you can’t verify the checked state, stop without submitting.
without a wallet item, card creation fails because spec.wallet must reference a wallet from the same vault and provider. with an unconnected link wallet, card creation returns a conflict. with an unconnected agentcard wallet, a card without card_id can remain requested, while a pinned card_id cannot be validated. neither path is ready for checkout.

Try with a coding agent

connect the provider wallet first through your controller or a human-operated terminal. these prompts require exactly one connected wallet for the chosen provider in user-12345 and a coding agent with access to the KERNEL cli. complete the prerequisites, including verifying the payment mode and identifying your merchant order record. replace the checkout url with a low-value checkout you control. the coding agent must stop whenever a provider action is required: cli output can contain the action url. keep enrollment, authorization actions, and approval observation outside that agent. the prompts repeat the safety requirements so they remain self-contained when copied.