Dexter
Dexter
Docs

Session Client

The session client SDK handles the full buyer lifecycle: onboarding, session open, per-request payment with vouchers, and session close with on-chain settlement.

Quick Start

import { createSessionClient } from '@dexterai/mpp/client/session';
 
const session = createSessionClient({
  buyerWallet: 'YourWallet...',
  buyerSwigAddress: 'YourSwigWallet...',
});
 
// One-time: provision Swig wallet + grant Dexter delegation
await session.onboard({ signer: keypair });
 
// Open a session with a seller
const channel = await session.open({
  seller: 'SellerWallet...',
  deposit: '1000000', // 1 USDC
});
 
// Pay per request
for (const task of tasks) {
  const voucher = await session.pay(channel.channel_id, {
    amount: cumulative.toString(),
    serverNonce: nonce,
  });
 
  const res = await fetch(sellerUrl, {
    headers: { 'x-mpp-voucher': JSON.stringify(voucher) },
  });
 
  cumulative += pricePerUnit;
}
 
// Close and settle
await session.close(channel.channel_id);

Parameters

ParameterTypeDefaultDescription
buyerWalletstringrequiredBuyer's Solana wallet address
buyerSwigAddressstringrequiredBuyer's Swig smart wallet address
apiUrlstringhttps://x402.dexter.cashSettlement API base URL
networkstringmainnet-betaSolana cluster
onProgressfunctionnoneCallback for lifecycle progress events

Onboarding

Onboarding is a one-time process that provisions a Swig smart wallet and grants Dexter a scoped delegation role. The buyer proves wallet ownership with a SIWx (Sign-In-With-X) signature.

With @solana/kit (v2)

import { createKeyPairSignerFromBytes, getBase58Encoder } from '@solana/kit';
 
const signer = await createKeyPairSignerFromBytes(
  getBase58Encoder().encode(process.env.SOLANA_PRIVATE_KEY),
);
 
await session.onboard({ signer });

The SDK detects a Kit v2 CryptoKeyPair signer and uses it for both the SIWx proof and the Swig transaction signatures.

With @solana/web3.js (v1)

import { Keypair } from '@solana/web3.js';
import bs58 from 'bs58';
import nacl from 'tweetnacl';
 
const keypair = Keypair.fromSecretKey(bs58.decode(process.env.SOLANA_PRIVATE_KEY));
 
await session.onboard({
  signMessage: async (message: Uint8Array) =>
    nacl.sign.detached(message, keypair.secretKey),
  publicKey: keypair.publicKey.toBase58(),
  signTransaction: async (tx) => {
    tx.sign(keypair);
    return tx;
  },
});

Onboard Options

ParameterTypeDescription
signerCryptoKeyPairKit v2 signer. Handles SIWx and transaction signing.
signMessage(msg: Uint8Array) => Promise<Uint8Array>Alternative: raw Ed25519 message signing function
publicKeystringRequired with signMessage: wallet public key as base58
signTransaction(tx) => Promise<tx>Required with signMessage: transaction signing function

Provide either signer (Kit v2) or signMessage + publicKey + signTransaction (web3.js / custom).

Session Lifecycle

open(params)

Opens a payment channel with a seller. Dexter verifies the buyer's Swig delegation role on-chain and creates the channel.

const channel = await session.open({
  seller: 'SellerWallet...',
  deposit: '1000000', // 1 USDC deposit (spend limit)
});
 
// channel.channel_id — unique channel identifier
// channel.session_pubkey — per-session signing key
ParameterTypeDescription
sellerstringSeller's Solana wallet address
depositstringSpend limit in atomic USDC units

pay(channelId, params)

Requests a signed voucher from Dexter for a cumulative payment amount.

const voucher = await session.pay(channel.channel_id, {
  amount: '30000', // cumulative total, not incremental
  serverNonce: nonce, // from the seller's 402 challenge
});

The amount is cumulative, not incremental. If you've made three requests at 10,000 each, the third voucher's amount is 30000, not 10000.

ParameterTypeDescription
amountstringCumulative total in atomic USDC units
serverNoncestringNonce from the seller's challenge response

close(channelId)

Closes the session and triggers on-chain settlement. Dexter executes a TransferChecked from the buyer's Swig wallet to the seller for the cumulative amount consumed.

const result = await session.close(channel.channel_id);
// result.signature — on-chain transaction signature

Any deposit amount beyond what was consumed is not transferred. The buyer retains the unspent balance.

Progress Events

Track lifecycle events with the onProgress callback:

const session = createSessionClient({
  buyerWallet: '...',
  buyerSwigAddress: '...',
  onProgress: (event) => {
    console.log(event.type, event.message);
  },
});

Event types: open, voucher, close, error.

On this page