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

# Your own browser

> Use Agentcard with a browser you run yourself to let your agent make purchases with your users' cards.

You don't need a browser provider. If your agent drives its own Chromium, locally or on your infrastructure, the Vault attaches to it the same way it attaches to KERNEL or Browserbase. There are three levels, depending on how much of the browser you control.

You need a user with a card in the Vault first. See [Adding a card](/vault/adding-a-card).

## Level 1: You use Playwright

Attach to your Playwright page. This is the same code as every other browser, with your own launch instead of a provider's.

```bash theme={null}
npm i @agent-cards/checkout playwright
```

```ts theme={null}
import { chromium } from 'playwright';
import { VaultClient, attachToPlaywright } from '@agent-cards/checkout';

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ serviceWorkers: 'block' });
const page = await context.newPage();

const vault = new VaultClient({
  clientId: process.env.AGENTCARD_CLIENT_ID!,
  clientSecret: process.env.AGENTCARD_CLIENT_SECRET!,
});
await vault.syncRegistry();

const checkout = await attachToPlaywright(page, {
  vault,
  user: 'usr_8f3k2m',
  merchant: 'shop.example.com',
  amount: 2306,
  currency: 'usd',
  onApprovalUrl: (url) => sendToUser(url),
});

// Now let the agent shop.
await page.goto('https://shop.example.com');
```

A remote Chromium works too: replace `chromium.launch()` with `chromium.connectOverCDP(yourCdpUrl)`.

## Level 2: You speak CDP directly

Pass `attachToCdp` your browser-level CDP connection and the session id of the tab your agent checks out in. When your agent submits the placeholder card in that tab, the SDK pauses the request to the payment processor and calls `onApprovalUrl` with the link the user opens to approve.

```ts theme={null}
import { VaultClient, attachToCdp } from '@agent-cards/checkout';

const vault = new VaultClient({
  clientId: process.env.AGENTCARD_CLIENT_ID!,
  clientSecret: process.env.AGENTCARD_CLIENT_SECRET!,
});
await vault.syncRegistry();

const { browserContextId } = await myCdpConnection.send('Target.createBrowserContext');
const { targetId } = await myCdpConnection.send('Target.createTarget', { url: 'about:blank', browserContextId });
const { sessionId: pageSessionId } = await myCdpConnection.send('Target.attachToTarget', { targetId, flatten: true });

const checkout = await attachToCdp(myCdpConnection, pageSessionId, {
  vault,
  user: 'usr_8f3k2m',
  merchant: 'shop.example.com',
  amount: 2306,
  currency: 'usd',
  onApprovalUrl: (url) => sendToUser(url),
});

// Now let the agent shop.
await myCdpConnection.send('Page.navigate', { url: 'https://shop.example.com' }, pageSessionId);
```

Keep the connection at the browser level, because the card fields load in cross-origin iframes and the SDK attaches to each iframe as its own CDP target. Wrap your connection in the `CdpLike` type the SDK exports: a `send(method, params, sessionId)` that resolves with the command's result and rejects on a CDP error, and an `on(handler)` that receives every event with the session id it came from. Attach to the tab with `flatten: true`, as the sample does, so each command and event carries that session id.

Open the checkout tab in a fresh browser context, as the sample does with `Target.createBrowserContext`. An extension page or a service worker in the tab's context can send the card to the payment processor in a request the SDK cannot pause, so `attachToCdp` refuses that context and throws:

```text theme={null}
CheckoutAttachmentError: Could not attach checkout interception. Close this checkout page and retry in a fresh browser context.
```

Close that tab with `Target.closeTarget`. If your code created the tab's context, dispose it with `Target.disposeBrowserContext`. Then open the checkout again with the sample's three `Target` calls.

A shop can also register a service worker after you attach. `attachToCdp` has already returned by then, so nothing throws. The checkout stops instead, and `checkout.getState()` returns:

```text theme={null}
{"status":"outcome_unknown","authorizationId":null,"reason":"browser_interception_unavailable"}
```

Check out on a shop like that through Level 1. Playwright's `serviceWorkers: 'block'` stops the shop from registering a service worker, so the checkout keeps working.

## Level 3: You do your own interception

If you already intercept network requests in your browser, skip the SDK and make the authorization call yourself. When your agent submits the placeholder card and you see the request to the payment processor, pause it and send it to Agentcard:

```bash theme={null}
curl -X POST https://api.agentcard.sh/api/v2/checkout/authorizations \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "usr_8f3k2m",
    "merchant": "shop.example.com",
    "amount": 2306,
    "currency": "usd",
    "psp": "stripe",
    "request": {
      "url": "https://api.stripe.com/v1/tokens",
      "method": "POST",
      "headers": { "content-type": "application/x-www-form-urlencoded" },
      "body": "card[number]=<card number>&..."
    }
  }'
```

The response carries `approvalUrl` to send the user. Poll `GET /v2/checkout/authorizations/:id` until it is `approved`, then fulfill the paused request with the processor `response` from the authorization. Two things to get right:

* **CORS.** Stripe and most processors are called cross-origin. Your fulfilled response must carry `access-control-allow-origin` set to the paused request's own `Origin` header, plus `access-control-allow-credentials: true`, or the page rejects it. The SDK exports `withCorsHeaders` for this.
* **Recognized processors only.** `GET /v2/checkout/recognizers` lists the processor endpoints Agentcard can complete. Pause those, and leave everything else untouched.

## Next

Whichever level you pick, the rest of the flow is identical: placeholder card, passkey approval, real card swapped in, confirm with the merchant. Follow the [Vault Quickstart](/vault/quickstart) from step 4, or read [Completing a purchase](/vault/completing-a-purchase).


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