Pay machine-payable endpoints from any agent. This client speaks the x402 "exact" scheme over Permit2 witness transfers: it catches an HTTP 402 challenge, signs a stablecoin authorization, and retries the request. Built for tokens without EIP-3009 support, starting with USDG on Robinhood Chain (eip155:4663).
The buyer wallet only ever needs the stablecoin. Payments are signatures (the merchant's relayer pays settlement gas), and the one-time Permit2 approval can be gas-sponsored by a gateway.
npm install @meshgateway/mpp-client viemimport { createClient, getSettlement } from '@meshgateway/mpp-client';
import { privateKeyToAccount } from 'viem/accounts';
const client = createClient({
signer: privateKeyToAccount(process.env.BUYER_PRIVATE_KEY),
maxAmount: '0.05', // spend cap per request, display units
});
const res = await client.fetch(
'https://api.meshgateway.com/m/acme-signals/v1/quote',
);
console.log(await res.json());
console.log(getSettlement(res)); // { transaction, network, payer }client.fetch is a drop-in fetch: responses that are not a 402 pass through
untouched. When the response is a 402 with a permit2 offer at or below your
maxAmount, the client signs and retries once. Anything else throws a
MppClientError with a code explaining why (no-permit2-offer,
over-max-amount, payment-rejected).
Permit2 needs a single on-chain approval per token. Wallets holding only the stablecoin can have the gas sponsored:
import { ensurePermit2Approval } from '@meshgateway/mpp-client';
import { privateKeyToAccount } from 'viem/accounts';
await ensurePermit2Approval({
account: privateKeyToAccount(process.env.BUYER_PRIVATE_KEY),
token: '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168', // USDG
chainId: 4663,
rpcUrl: 'https://your-robinhood-rpc',
sponsorUrl: 'https://meshgateway.com', // POST /api/gas/sponsor
});For custom flows, the building blocks are exported directly:
parseChallenge(response)decodes thepayment-requiredheader of a 402selectPermit2Offer(challenge)picks the permit2 offer fromaccepts[]signPermit2Payment(signer, offer)returns thepayment-signatureheadergetSettlement(response)decodes thepayment-responsesettlement proof
GETthe resource. The server answers402 Payment Requiredwith a base64 JSONpayment-requiredheader listing offers (token, atomic amount, recipient, spender).- The client signs an EIP-712
PermitWitnessTransferFromagainst the canonical Permit2 contract. The spender is pinned to the x402ExactPermit2Proxy (0x402085...20001) and the witness pins the recipient, so the signature cannot be redirected. - The client retries with the signed payload in the
payment-signatureheader. The server verifies, a relayer broadcastssettle, and the token moves straight from payer to merchant. The response carries apayment-responseheader with the settlement transaction hash.
- The signature authorizes one exact transfer to one recipient with a short deadline and a random nonce. It cannot be replayed or redirected.
maxAmountis enforced client-side before anything is signed.- The client never holds keys beyond the viem account you pass in.
- v0 supports the permit2 transfer method only. For EIP-3009 networks
(USDC on Base) use the upstream
mppxclient. - Planned: browser wallet signers, EIP-3009 support, batch payments.
Server counterpart: meshgateway/mpp-server. Hosted gateway and marketplace: MeshGateway.
MIT