Quickstart#

Get up and running with xenga escrow payments in 5 minutes.

Install#

npm install @xenga/client viem
# or
bun add @xenga/client viem

1. Pay for an order with escrowFetch#

The simplest integration. escrowFetch wraps fetch() and handles the entire xenga payment flow automatically:

import { escrowFetch } from "@xenga/client";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
 
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({
  chain: baseSepolia,
  transport: http(),
  account,
});
 
// Just like fetch(), but handles 402 payment flow automatically
const { response, payment } = await escrowFetch(
  "https://api.xenga.xyz/api/orders/ORDER_ID/pay",
  { method: "POST" },
  { walletClient }
);
 
console.log("Escrow ID:", payment?.escrowId);
console.log("TX Hash:", payment?.txHash);

What happens under the hood:

  1. Client sends POST without payment header
  2. Server returns 402 with payment requirements in headers
  3. Client signs an ERC-3009 receiveWithAuthorization (USDC gasless transfer)
  4. Client retries with PAYMENT-SIGNATURE header
  5. Server verifies signature, creates escrow on-chain (including contentHash if order has terms), returns 200

The contentHash is a keccak256 hash of the order terms stored immutably on-chain. It provides tamper-proof evidence of the agreed-upon terms for dispute resolution.

2. Using the full client SDK#

For more control, use createEscrowClient:

import { createEscrowClient } from "@xenga/client";
 
const client = createEscrowClient({
  privateKey: "0xYOUR_PRIVATE_KEY",
  serverUrl: "https://api.xenga.xyz",
  escrowVaultAddress: "0xCONTRACT_ADDRESS", // for on-chain calls
  chainId: 84532, // Base Sepolia (default). Use 8453 for Base Mainnet.
});
 
// Pay for an order (handles full xenga flow)
const { order, payment } = await client.payForOrder("ORDER_ID");
 
// Release funds (buyer confirms receipt)
const txHash = await client.releaseOnChain(payment.escrowId);
 
// Or dispute (within dispute window)
const txHash2 = await client.disputeOnChain(payment.escrowId);

Seller operations#

// Confirm delivery (starts dispute window countdown)
await client.confirmDeliveryOnChain(escrowId);
 
// Voluntary refund
await client.refundOnChain(escrowId);
 
// Check on-chain stats
const stats = await client.getSellerStats();
console.log(`Completed: ${stats.completedCount}/${stats.totalEscrows}`);
 
// Check ETH balance before transacting
const { eth } = await client.getBalance();
console.log(`ETH balance: ${eth}`);

3. Check seller reputation before paying#

const { response, payment } = await escrowFetch(
  url,
  { method: "POST" },
  {
    walletClient,
    onSellerReputation: (rep) => {
      if (rep.score < 50) {
        console.log("Low reputation seller, aborting");
        return false; // abort payment
      }
      return true; // proceed
    },
  }
);

Next steps#

  • Agent Guide — end-to-end scenarios for AI agents, reputation screening, dispute handling
  • API Reference — all endpoints, request/response schemas, error codes
  • Seller Guide — webhooks, on-chain seller actions, fee structure