Skip to main content
The Agent Vault SDK lets an Agent pay on a merchant’s checkout page without ever handling the user’s real card. The Agent fills a public placeholder card. The SDK intercepts the page’s request to the merchant’s payment service provider (PSP), and Clink Vault swaps in the real card inside Clink’s PCI boundary before calling the PSP. Handing a real card number to an LLM or a script creates serious compliance and leakage risks. With the SDK, the Agent keeps control of the page, while card data and authorization checks stay with Clink. For every method and option, see the SDK reference.

How it works

  1. Intercept. The SDK attaches to the browser your Agent drives (Playwright or raw CDP) and intercepts requests from the page and every cross-origin iframe.
  2. Placeholder card. The SDK returns a public test card of the same brand as the user’s real card, such as Visa 4111 1111 1111 1111 with the real card’s expiry. The Agent fills it into the checkout form.
  3. Match. When the page sends a tokenization request to the PSP, the SDK matches it against reviewed PSP rules (host, path, and fields). It pauses the request only if the card fields equal the placeholder card issued for this checkout.
  4. Relay. The SDK sends only the request template, a placeholder marker, the card_token, and allowlisted request headers to Clink Vault.
  5. Substitute. Clink Vault checks the 30-minute payment window and the PSP rule, replaces the placeholder with the real card inside the PCI boundary, and calls the PSP directly.
  6. Replay. The SDK replays the PSP’s original status code, headers, and body to the page, which continues the order as with any normal payment.

Visible to the Agent and browser

  • Card brand and last four digits
  • A placeholder test card of the same brand
  • Card setup links and payment status
  • The PSP’s native response to the page

Only inside Clink's PCI boundary

  • The real card number (PAN) and CVV, stored with KMS encryption
  • Checks on the payment window and PSP rules
  • The request sent to the PSP with the real card
  • Card ciphertext for client-side encryption PSPs such as Adyen
Payments go through the merchant’s own PSP; Clink sees only the PSP’s HTTP response. A 2xx response from the tokenization endpoint means the card was tokenized, not that the order was charged. Use the order result on the merchant page as the final outcome and report it with reconcile().

Get started

Run the SDK on your application server or in a trusted checkout worker, never in the user’s browser.
1

Install the SDK

2

Attach to the checkout page

Create a client, then attach it to the page your Agent drives. Pass email so the SDK can start card setup when the user has no usable card.
vault.attach(page) works with Playwright, locally or on a cloud browser through connectOverCDP, and covers cross-origin iframes. Without Playwright, such as over a cloud browser WebSocket, use vault.attachToCdp(cdp, sessionId, options). Both return the same CheckoutController.
3

Call pay() until it returns a final status

Each pay() call returns the next thing the Agent should do in next_action. Perform it, then call pay() again. fillCard and clickPayButton are your own page functions; see Code examples.
4

Reconcile and detach

waitForOrderResult is your own page function: it polls readOrderResult until the page shows a result or the timeout passes. See card-form.ts in Code examples. This wait covers the user scanning a QR code or completing 3DS or a redirect after the loop stops at wait_user, and the order page loading after succeeded.reconcile() reads the merchant’s order result through resolveMerchantResult and reports it to Clink Vault. Always call detach() when checkout ends.If no card request reached the PSP, or resolveMerchantResult is not set, reconcile() returns the current state unchanged. See Handle the result.
Before paying, you can call checkout.getPaymentMethods() to see which methods the page supports. A card’s status is ready, needs_bind, or unsupported. QR wallets and PayPal on the page are needs_user: ask the user first, then start them with pay({ method }). See PSP coverage.

When the user needs to act

Vault does not use passkeys, SMS codes, or per-payment confirmation links. The user opens a card setup link once: they add a new card, or choose an existing card and re-enter its CVV. This opens a 30-minute payment window, during which the Agent completes fill_card → submit without the user. Clink hosts the card setup page; it requires no sign-in and can be used once. When next_action.type is wait_user, its reason tells you what the user needs to do. The same action is also passed to onUserAction.
Notifications. Clink does not send the user SMS, email, or payment notifications. Your code delivers the card setup link through your own UI, messages, or notification channels. Do not let an LLM compose or rewrite the link.
You can also start card setup without waiting for pay(): call checkout.bind() during checkout, or vault.sessions.create({ email }) outside checkout. New cards and CVV re-entry use the same link. Call vault.cards.list({ customerId }) to see a user’s cards and when their windows expire.

Handle the result

Common reason values with failed:
  • card_not_bound: No usable card exists, and no email was passed, so the SDK cannot start card setup.
  • window_expired: The 30-minute payment window has expired, and no email was passed. With email, pay() returns wait_user (bind_card) instead, and the user selects this card and re-enters its CVV.
  • card_frozen or token_revoked: The card is frozen, or its card token has been revoked. Ask the user to set up another card with checkout.bind().
  • placeholder_mismatch: The page request contained a card number or CVV other than the placeholder card. The SDK refused to let it through.
  • checkout_request_not_seen: No PSP request was intercepted within 30 seconds of submit. Check that the pay button was actually clicked.
  • session_expired: The card setup session failed or was locked. Call retry(), then pay() to generate a new link. A link that has only expired does not cause this error; pay() generates a new link automatically.
  • card_token_missing or card_token_not_found: Card setup completed, but the session carried no card token, or the token is not in the card list. The SDK does not start card setup again; investigate the server-side data.
  • merchant_declined: The PSP authorized the payment, but resolveMerchantResult reported failed, and reconcile() recorded it. Call retry() to try again.
  • paypal_redirect_url_not_found: No PayPal approval link was found within 30 seconds (submitTimeoutMs) of clicking pay with PayPal.
  • cancelled: cancel() or detach() was called before the payment had a result.
  • api_error or network_error: A call to Clink Vault was rejected or could not reach the API, for example because the client credentials are invalid. Check the credentials and network, then try again.
With unsupported:
  • rule_not_matched or psp_unsupported: The page’s PSP request matched no enabled rule. See PSP coverage.
  • unsupported_card_brand: The user’s card brand has no placeholder card.
  • card_encrypted: The page encrypted the card fields and sent them to an endpoint no rule covers, such as the merchant’s own server.
  • cse_request_unsupported: An Adyen request the SDK does not relay, such as saving the card or paying with a stored card.
With outcome_unknown:
  • pay_qr_unavailable: No usable QR code was found after submission. The merchant may have accepted the order, so do not switch to a card automatically.
  • psp_timeout, missing_response, or merchant_result_unknown: The PSP did not answer in time, Clink Vault returned no PSP response, or resolveMerchantResult returned unknown or threw. Verify the order before taking any other action.

PSP coverage

The SDK syncs matching rules from the server during attach, so supporting a new standard PSP requires a rule update rather than a new SDK release. If rule sync fails because of a network error, timeout, 429, or 5xx, or returns a malformed response, the SDK falls back to its built-in rules. Any other error from Clink, such as 401 or 403, does not fall back: attach still succeeds but loads no rules, so a card request on the page returns unsupported (rule_not_matched). With invalid client credentials, pay() fails earlier with failed (api_error). The SDK covers one-time payments with the placeholder card typed into the page. Leave any option on the merchant page to save the card turned off. If the page pays with a card the merchant already stores, that request carries no placeholder and does not go through Clink Vault.
  • Token mode. The page sends the placeholder card in plain text, and Clink Vault substitutes the real card. Covers 18 PSPs with 80 built-in rules: Stripe, Checkout.com, Airwallex, Rapyd, Global Payments, Square, Authorize.net, Nuvei, EBANX, Mercado Pago, PayU, Razorpay, Mollie, Paysafe, Recurly, Bambora, Spreedly, and Shopify.
  • CSE mode. For Adyen Sessions payments (checkoutshopper-*.adyen.com), enabled. The SDK recognizes adyen-web JWE ciphertext and legacy securedFields 3.x adyenjs_0_1_* ciphertext. The server encrypts the real card with the Adyen public key and sends the request, so neither the page nor the Agent sees the ciphertext.
  • Not yet supported. Braintree, Worldpay, dLocal, Stripe Checkout Session confirm, Hosted Form, and merchant self-hosted Adyen. The SDK returns unsupported, and the encrypted placeholder card is not sent.
Placeholder cards are available for Visa, Mastercard, American Express, Discover, JCB, and UnionPay. For other card brands, pay() returns unsupported (unsupported_card_brand). Besides cards, the SDK supports two payment methods that are completed entirely in the browser. They do not use Clink Vault authorization and send no card token. The page must already offer the method; the SDK does not create orders or generate QR codes.
  • QR code payment (paynow, wechat_pay, upi_qr, pix, bcmc_mobile). The SDK extracts that wallet’s own QR code from the page or an iframe, skipping logos and other wallets’ codes, and returns it as a PNG. For PayNow, the expiry is read from the QR code; other methods default to 10 minutes. Use reconcile() for the payment result.
  • PayPal link (paypal). After the Agent selects PayPal and clicks pay, call pay({ method: 'paypal' }) once to get the paypal.com approval link. What the user does on PayPal afterwards is outside the SDK.
fallback: 'card' applies only to QR code payments. The SDK falls back to a card only when resolveMerchantResult explicitly returns { status: 'failed', payment_confirmed_unpaid: true }. An unknown or pending result, or a QR code that expired locally, never triggers an automatic fallback.

Code examples

These examples run on your server. Merchant checkout pages differ, so adapt the selectors and page checks to the checkout your Agent automates.

Complete checkout

checkout.ts runs one card payment from attach to reconcile. card-form.ts fills the placeholder card, clicks pay, and reads the merchant’s order result. loadVaultCard, saveVaultCard, notifyUser, and showQrCode are your application’s own functions.

Expose payment steps as Agent tools

When an LLM decides each step, give it tools that advance the payment rather than card values. The model sees only the status and the next step. Your code fills the card, and resolveMerchantResult reads the order result from the page, so the model cannot report a success that the merchant did not show.
agent-tools.ts

Use a cloud browser

The SDK does not launch or manage a browser. For a cloud browser, attach to the page your Agent already drives, then run the same pay() loop.
Keep the cloud browser’s API key and your Clink client secret on the server; do not pass them to the Agent. For 3DS, show the user the cloud browser’s live view so they can complete verification.