Local TypeScript SDK for the current MicroAI Paygate x402-style protocol.
The SDK handles the existing gateway flow:
- Send an unsigned request.
- Read the
402 Payment RequiredpaymentContext. - Sign the payment context with EIP-712.
- Retry with the signed
X-402-*headers (v2 also includes the recoveredX-402-Payer). - Decode the
X-402-Receiptresponse header. - Verify the signed receipt locally.
This package is private and local for now. It is not published to npm.
MicroAI Paygate currently uses a custom x402-style wire contract. It is not official x402-compatible yet because it uses custom X-402-* headers and does not perform facilitator-backed or on-chain USDC settlement.
A valid EIP-712 signature proves wallet authorization for the payment context. It does not prove that USDC moved on-chain.
The SDK accepts the current legacy context and the staged request-bound v2 context. For v2 it verifies the audience, method, encoded path and raw query, content type, and SHA-256 hash of the exact serialized body before opening the wallet signature prompt. The public gateway remains on v1 until the separate cutover change is deployed.
cd sdk/typescript
bun install
bun run testRun the type checker:
bun run typecheckimport { ethers } from "ethers";
import { PaygateClient } from "@microai/paygate-sdk";
const client = new PaygateClient({
gatewayUrl: "http://localhost:3000",
signer: new ethers.Wallet(process.env.EVM_PRIVATE_KEY!),
trustedServerPublicKey: process.env.PAYGATE_SERVER_PUBLIC_KEY,
});
const response = await client.summarize("Text to summarize");
console.log(response.data.result);
console.log(response.receipt?.receipt.id);
console.log(response.receiptVerified);Generic endpoint usage:
const response = await client.request<{ text: string }, { result: string }>({
method: "POST",
path: "/api/ai/summarize",
body: { text: "..." },
});Set environment variables:
PAYGATE_GATEWAY_URL=http://localhost:3000
EVM_PRIVATE_KEY=0x...
PAYGATE_SERVER_PUBLIC_KEY=0x...
Use only unfunded local or test wallets. Never use a funded wallet, seed phrase, production key, or real customer wallet in examples.
PAYGATE_SERVER_PUBLIC_KEY should be the gateway receipt signing public key distributed out of band. Without it, the SDK can decode receipts and verify request/response hash binding, but it returns receiptVerified: false instead of trusting the self-declared key inside the receipt.
Run:
cd sdk/typescript
bun run examples/summarize.ts "Text to summarize"Receipt verification with a trusted public key (replace the placeholder with the gateway's real public key):
import { ethers } from "ethers";
import { PaygateClient, PaygateSdkError } from "@microai/paygate-sdk";
async function main(): Promise<void> {
const client = new PaygateClient({
gatewayUrl: process.env.PAYGATE_GATEWAY_URL ?? "http://localhost:3000",
signer: new ethers.Wallet(process.env.EVM_PRIVATE_KEY!),
trustedServerPublicKey: process.env.PAYGATE_SERVER_PUBLIC_KEY ?? "0xYOUR_GATEWAY_PUBLIC_KEY",
});
try {
const response = await client.summarize("Text to summarize");
if (!response.receipt) {
console.warn("No receipt returned; treat the response as untrusted.");
return;
}
if (!response.receiptVerified) {
console.warn("Receipt was present but did not verify; discard the response.");
return;
}
console.log("Verified receipt ID:", response.receipt.receipt.id);
console.log("Summary:", response.data.result);
} catch (error) {
if (
error instanceof PaygateSdkError &&
(error.code === "receipt_verification_failed" || error.code === "receipt_decode_failed")
) {
console.error("Receipt verification failed; treat the response as untrusted.");
return;
}
throw error;
}
}
await main();Run the receipt verification example:
cd sdk/typescript
bun run examples/verify-receipt.ts "Text to summarize"The live SDK test is skipped by default. Start the local stack first:
bun run stackThen run:
PAYGATE_SDK_LIVE_TEST=1 EVM_PRIVATE_KEY=0x... PAYGATE_SERVER_PUBLIC_KEY=0x... PAYGATE_GATEWAY_URL=http://localhost:3000 bun test src/__tests__/live-gateway.test.tsThe live path depends on the gateway's configured AI provider. With the default OpenRouter provider, the gateway still needs OPENROUTER_API_KEY.