> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clinkbill.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Vault SDK platform setup

> Configure the platform boundary around Agent Vault SDK without duplicating the SDK payment guide.

This page covers the platform layer around Agent Vault SDK: server credentials, user and card associations, browser ownership, and rollout checks. Vault SDK can coexist with Browser Pay in the same platform; route a checkout to one path before the payment attempt starts. It does not repeat the SDK state machine or PSP behavior. For `attach()`, `pay()`, `reconcile()`, states, errors, and complete code, use the [Agent Vault SDK guide](https://docs.clinkbill.com/guides/agent/vault_sdk) and [SDK API reference](https://docs.clinkbill.com/guides/agent/vault_sdk/api_reference.md).

> [!NOTE]
>
> Vault SDK does not require end-user OAuth and does not connect to a user's MCP. The platform server uses Clink application credentials with OAuth `client_credentials`; the user only participates in hosted card setup or merchant verification when the payment flow requires it.

## Provision the server integration

Run the SDK in a trusted platform service or checkout worker that controls a Playwright or CDP browser. The Agent and merchant page must see only the SDK placeholder card.

| Item | Platform requirement |
| - | - |
| Package | `@clink-ai/agent-vault` and Playwright when using a Playwright `Page`. |
| Credentials | A Vault `client_id` and `client_secret` issued by Clink. The SDK obtains and refreshes application tokens with `client_credentials`. |
| Environment | `sandbox` for UAT and `production` for live traffic. Keep credentials and card associations separate. |
| Browser boundary | The platform owns navigation, product selection, shipping fields, and the merchant result. The SDK attaches to the checkout page and supported PSP requests. |
| Coverage | `vault.getCoverage()` lists the PSPs enabled in the environment; it does not list merchants. Confirm target merchants with Clink's coverage list, and use `checkout.getPaymentMethods()` to check a specific checkout page. |

Keep the Client Secret, `cardToken`, and any server-side card association on the trusted platform server. Do not expose them to a model, Agent tool, browser storage, logs, or user-facing messages.

## Model user and card state

Use the platform's stable user ID as `externalUserId`. Do not use an email address as the primary key; email changes must not silently attach a card to another platform user.

| Data | Platform responsibility |
| - | - |
| `externalUserId` | Stable platform user key passed to Vault. Keep one association per platform tenant and environment. |
| `email` | Verified address used to create a hosted card setup session. Treat it as changeable user data. |
| `customerId` | Vault customer association, returned by `sessions.create()` and `onCardBound`. Save it with the platform user and environment once setup completes. |
| `cardToken` | Server-only token for the saved card. Pass it back to `attach()`; never send it to the Agent or merchant page. |
| `sessionId` and `url` | Short-lived hosted setup context. The creation response is not a usable card credential. Deliver `url` unchanged to the user. |
| `window.expiresAt` | Deadline for the payment window returned with a usable card. Treat an expired window as a new user-action branch. |

Confirm with Clink how `externalUserId`, email, and `customerId` behave when a user changes email, deletes or freezes a card, or accounts are merged. Do not infer those matching rules from the SDK method names.

## Bind or reuse a card

For a returning user, load the saved `customerId` and `cardToken` on the server. For first use or an expired window, pass `email` to `attach()`: `pay()` then returns `wait_user` / `bind_card` with a hosted setup link, and `onCardBound` returns the card association once setup completes. You can also create a setup session before checkout and read its result after the user finishes:

```typescript theme={null}
const session = await vault.sessions.create({
  email: currentUser.email,
  externalUserId: currentUser.id,
});
await deliverUserAction(currentUser.id, { type: 'bind_card', url: session.url }); // url unchanged

// The user completes setup from the link; poll until the session ends
let result = await vault.sessions.retrieve(session.sessionId);
while (result.status === 'pending' || result.status === 'opened') {
  await new Promise(resolve => setTimeout(resolve, 5_000));
  result = await vault.sessions.retrieve(session.sessionId);
}
if (result.status === 'completed' && result.cardToken) {
  await saveVaultCard(currentUser.id, {
    customerId: session.customerId, // returned by sessions.create()
    cardToken: result.cardToken,
  });
}
```

The `sessionId` and `url` returned on creation are not card credentials. Save `customerId` and `cardToken` only after the session completes: `customerId` comes from `sessions.create()`, and `cardToken` from the completed session. Use the SDK's current `expiresAt` and card status when deciding whether a saved association can be reused.

## Attach the platform browser

Attach one checkout controller to the browser task that owns one merchant checkout. Pass the platform user association and callbacks that deliver user actions and read the merchant result:

```typescript theme={null}
const checkout = await vault.attach(page, {
  customerId: savedCard?.customerId,
  cardToken: savedCard?.cardToken,
  email: currentUser.email,
  externalUserId: currentUser.id,
  onUserAction: action => deliverUserAction(currentUser.id, action),
  onCardBound: card => saveVaultCard(currentUser.id, card),
  resolveMerchantResult: () => readMerchantOrderResult(page),
});
```

With raw CDP, use `vault.attachToCdp()`. Do not share a controller, page session, `customerId`, or `cardToken` across platform users. Close or detach the controller when that checkout ends.

During `checkout.pay()`, first-time setup and an expired payment window surface as the same `wait_user` / `bind_card` action. The platform should:

* deliver the hosted setup link unchanged;
* wait for the user to add a card or re-enter its CVV;
* persist the `customerId` / `cardToken` returned by `onCardBound`; and
* continue the same checkout with the SDK placeholder card.

3DS, QR, and redirect actions belong to the current merchant browser or the user's device. Deliver the SDK action as returned and let the canonical [Agent Vault SDK guide](https://docs.clinkbill.com/guides/agent/vault_sdk) define how to continue and reconcile each method.

## Persist and recover the merchant result

The platform must read the merchant's order result through `resolveMerchantResult`; a PSP tokenization response or SDK status alone does not prove that the order completed. Use `reconcile()` and the result rules in the [Agent Vault SDK guide](https://docs.clinkbill.com/guides/agent/vault_sdk) to distinguish completed, failed, pending, user-action, and unknown outcomes.

Keep the same checkout controller while the merchant result is pending or requires user action, and call `reconcile()` again once the merchant page shows a result. When the result is unknown, verify the original order before taking any other action, and do not switch cards or start a second payment. Call `retry()` only after confirming that no charge occurred, and before `detach()`. Call `detach()` when the checkout ends; it releases interception resources and does not cancel a request already sent.

Store the merchant order number separately from Vault identifiers. The platform's user notification should be based on the merchant result, not only on a PSP response or a Clink report.

## Validate before rollout

Run these checks in Sandbox UAT and repeat the relevant checks in Production:

* Two platform users can pay concurrently without sharing a browser session, card association, payment window, or result context.
* A new user can complete hosted setup, receive `onCardBound`, and reuse the saved association on a later checkout.
* An expired window leads to a new `bind_card` action instead of an automatic card submission.
* The target PSP, card brands, QR methods, and PayPal behavior match the enabled coverage for the environment.
* 3DS, redirects, QR actions, merchant pending results, definite failures, and unknown results have explicit user and recovery handling.
* Pending and user-action results are reconciled again on the same controller, unknown results are verified before any further payment, and every checkout is detached when it ends.

## Confirm with Clink

Before production, confirm the Vault client credentials, target merchant and PSP coverage, `customerId` / `cardToken` reuse after expiry or card changes, and the matching rules for `externalUserId`, email, and customer records. Keep these values in deployment and data-model documentation.

## Related docs

* [Agent Vault SDK guide](https://docs.clinkbill.com/guides/agent/vault_sdk): SDK behavior, payment states, PSP coverage, and complete examples.
* [SDK API reference](https://docs.clinkbill.com/guides/agent/vault_sdk/api_reference.md): methods, options, return values, and error codes.
* [Browser Pay platform setup](https://docs.clinkbill.com/guides/agent/platform_integration/browser_pay.md): the alternative OAuth + MCP platform path.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.