Quickstart#
Get up and running with xenga escrow payments in 5 minutes.
Install#
npm install @xenga/client viem
# or
bun add @xenga/client viem1. 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:
- Client sends POST without payment header
- Server returns
402with payment requirements in headers - Client signs an ERC-3009
receiveWithAuthorization(USDC gasless transfer) - Client retries with
PAYMENT-SIGNATUREheader - Server verifies signature, creates escrow on-chain (including
contentHashif order hasterms), returns200
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