Dexter
Dexter
Docs

Charge Mode

Charge mode settles each payment individually on-chain. The seller's server interacts with two Dexter endpoints. Dexter handles fee payer co-signing, transaction simulation, broadcast, and confirmation. Buyers need zero SOL.

How It Works

sequenceDiagram
    participant Buyer
    participant Seller
    participant Dexter
    participant Solana
 
    Buyer->>Seller: GET /api/resource
    Seller->>Dexter: POST /mpp/prepare
    Dexter-->>Seller: fee payer + blockhash
    Seller-->>Buyer: 402 + challenge (amount, recipient, blockhash)
    Buyer->>Buyer: Build + sign USDC TransferChecked
    Buyer->>Seller: GET /api/resource + signed tx
    Seller->>Dexter: POST /mpp/settle (signed tx)
    Dexter->>Dexter: Validate security policy
    Dexter->>Dexter: Co-sign as fee payer
    Dexter->>Solana: Simulate + broadcast
    Solana-->>Dexter: Confirmed
    Dexter-->>Seller: Settlement proof (signature, recipient, amount)
    Seller-->>Buyer: 200 + data + MPP receipt

Server Setup

import crypto from 'node:crypto';
import { Mppx } from 'mppx/server';
import { charge } from '@dexterai/mpp/server';
 
const mppx = Mppx.create({
  secretKey: crypto.randomBytes(32).toString('hex'),
  methods: [charge({ recipient: 'YourSolanaWallet...' })],
});
 
app.get('/api/data', async (req, res) => {
  const result = await mppx.charge({
    amount: '10000', // 0.01 USDC (atomic units, 6 decimals)
    currency: 'USDC',
  })(toWebRequest(req));
 
  if (result.status === 402) return sendChallenge(res, result);
  return sendWithReceipt(res, result, { data: 'paid content' });
});

Server Options

ParameterTypeDefaultDescription
recipientstringrequiredSolana wallet address to receive payments
apiUrlstringhttps://x402.dexter.cashSettlement API base URL
networkstringmainnet-betaSolana cluster
splTokenstringUSDC mainnet mintSPL token mint address
decimalsnumber6Token decimal places
verifyRpcUrlstringnoneOptional RPC URL for independent on-chain verification

Client Setup

import { Mppx } from 'mppx/client';
import { charge } from '@dexterai/mpp/client';
import { createKeyPairSignerFromBytes, getBase58Encoder } from '@solana/kit';
 
const signer = await createKeyPairSignerFromBytes(
  getBase58Encoder().encode(process.env.SOLANA_PRIVATE_KEY),
);
 
Mppx.create({
  methods: [charge({ signer })],
});
 
// 402 responses are handled automatically. Buyer needs zero SOL.
const response = await fetch('https://api.example.com/paid');

Client Options

ParameterTypeDefaultDescription
signerTransactionSignerrequiredSolana Kit transaction signer
computeUnitPricenumbernonePriority fee in micro-lamports
computeUnitLimitnumbernoneCompute unit limit for the transaction
onProgressfunctionnoneCallback for settlement progress events

Prerequisites

  • Recipient wallet must have a USDC token account (any wallet that has held USDC has one)
  • Buyers need USDC, not SOL. Dexter sponsors all transaction fees.
  • Supported networks: mainnet-beta and devnet
  • USDC mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (mainnet), 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (devnet)

When to Use Charge vs Sessions

Use charge mode when:

  • Requests are infrequent or unpredictable
  • Each API call is independent
  • Simplest integration is the priority

Use sessions when:

  • Requests are frequent or continuous
  • You want to minimize on-chain transactions
  • The buyer is an agent running many sequential calls

On this page