Skip to content
DexterDocs
Tabs / Browser Tabs
Sections

Browser Tabs

A browser integration has two jobs: let the owner approve spending authority, then use a compatible session client to sign payments. Choose the approval and transaction-sponsorship path before wiring a payment button.

@dexterai/x402@6.0.0 supports context-bound V2 sessions and requires @dexterai/vault@0.43.4. A paid request also needs a reserveFinalVoucherV2 provider: an authenticated backend that confirms the exact signed reservation before the SDK releases the voucher. Keep the provider's authority and durable transaction handling on the server.

Use the Hosted Approval Flow

Dexter's hosted flow reviews the seller and the proposed limits, asks the owner for passkey approval, and handles registration sponsorship subject to eligibility checks. Your site keeps the agent's session secret on its own trusted runtime and supplies only the public key.

If you have a paid API URL, send the owner to /tabs/connect with the API's URL and the agent's session public key:

tab-approval-url.ts
import { PublicKey } from '@solana/web3.js';

export function tabApprovalUrl(serviceUrl: string, sessionPublicKey: string) {
  const service = new URL(serviceUrl);
  if (service.protocol !== 'https:') throw new Error('Use an HTTPS service URL.');

  const url = new URL('https://dexter.cash/tabs/connect');
  url.searchParams.set('url', service.href);
  url.searchParams.set('agent', new PublicKey(sessionPublicKey).toBase58());
  return url.href;
}

This helper uses @solana/web3.js@1. The resulting page reads the seller's x402 terms and lets the owner continue to approval. A URL that offers no tab produces a message instead of an approval request.

For your own cap, expiry, and callback, build a requestSpendGrant request and send it to /tabs/new?req=.... The Node grant guide includes a complete request generator and the callback contract. The URL-based lookup above does not configure a callback for your application.

Connect the Owner's Wallet

Follow Connect a Wallet with intent: 'wallet' and retain result.vault from the connection. That full Vault object supplies the owner's signer; registering a spending session still requires owner approval.

@dexterai/connect@0.29.1 exposes createPasskeySigner(vault). It creates the signer used for passkey-authorized Vault operations. Keep the connected account and authorization context current when asking the owner to sign.

Adapter Inputs

createSolanaVaultAdapter from @dexterai/x402/tab/adapters/solana takes these inputs in 6.0.0:

InputRequired value
connectionA Solana Connection for reads and transaction submission.
swigAddressThe Swig state account stored in vault.swig_address. The derived wallet address is a different account.
vaultPdaThe user's Dexter Vault account.
passkeySignerA PasskeySignerWithPublicKey for owner-authorized operations.
feePayerA funded Solana Signer, including its secret key, to pay transaction fees.

The adapter's required Signer belongs to a self-paying integration. A shared sponsor secret must stay on your server; embedding it in browser JavaScript exposes it to every visitor. A newly generated browser keypair also needs SOL before it can pay fees. Hosted sponsorship uses its own server flow and cannot be enabled by supplying a public fee-payer address to this adapter.

Reserve Before Delivery

Pass reserveFinalVoucherV2 to openTab or payUrlWithTab alongside the Vault adapter. It receives the complete voucher and a stable idempotency key; forward that identity unchanged to your backend. Return its FinalVoucherV2ReservationReceipt after confirmation. The adapter independently checks the reservation transaction, voucher-binding Memo, and matching Vault/session state.

The SDK exposes this provider contract rather than a ready-made reservation endpoint. Configure it with the backend authorized for your Vault before enabling paid requests. The Node integration shows the grant constructor and voucher header; the same receipt must accompany browser requests.

Session Lifecycle

The published API expresses two limits as human USDC strings: perUnitCap limits one voucher increase, and totalCap limits the session's cumulative spend. sessionDuration is in seconds.

openTab asks the adapter to register a session. The owner may need additional passkey approval for wallet activation or replacement. onLiveSession: 'error' refuses to replace an existing session for the same Vault and seller. Keep that behavior unless your application has reconciled the old session's unsettled vouchers.

signNextVoucher(amountAtomic) signs and reserves the requested increment before returning it. stream(url) in 6.0.0 signs the full perUnitCap once before reading the SSE response. Streaming output does not trigger additional per-chunk voucher exchanges.

Browser close() attempts settlement and then passkey-authorized revocation. Check the result's sessionRevoked field and preserve any settlement signature. An unused tab can have an empty settleTx; a failed close needs reconciliation before another attempt. See Close and Revoke.

Integration Failures

SymptomAction
Existing session blocks approvalInspect the old session and outstanding vouchers before replacing it.
Hosted registration is unavailableResolve the displayed eligibility or funding requirement before requesting approval again.
Adapter transaction lacks funds or a signerCheck the fee-payer transport; an owner passkey authorizes the operation but does not pay its SOL fee.
Voucher or reservation is rejectedPreserve the owner's grant values and include the full reservation receipt in the voucher header. Check the exact transaction and session state before retrying.
Settlement succeeded but revocation failedKeep the settlement receipt and complete revocation with the owner; paying again would create another charge.

Last Updated:

On this page