Nano payments and x402
Use Circle Gateway Nanopayments and x402 to pay Tachyon transaction relay costs in USDC with gasless, batched payment authorization.
Overview
Submit blockchain transactions through Tachyon and pay the relay cost in USDC using x402 and Circle Gateway Nanopayments.
What Is x402?
x402 is an open payment protocol built around the HTTP 402 Payment Required
status code. When a client calls a paid API, the server returns payment
requirements instead of requiring an account, subscription, or checkout page.
The client signs a payment authorization and retries the same request with the
payment proof attached. This allows applications and AI agents to pay for APIs
programmatically. Learn more about x402.
What Is Circle Gateway?
Circle Gateway provides a unified USDC balance that can be used across its
supported blockchain networks. A user deposits USDC into the Gateway Wallet
contract, after which applications can query the available balance and
authorize payments through the Gateway SDK. In this integration,
GatewayClient manages the deposit, balance, payment authorization, and
settlement details. Learn more about Circle Gateway.
What Are Nanopayments?
Circle Gateway Nanopayments are small USDC payments authorized with offchain signatures and settled onchain in batches. Instead of broadcasting a separate transaction and paying gas for every API request, buyers sign individual payment authorizations while Circle combines many payments into fewer settlement transactions. This makes high-frequency and sub-cent payments practical. Learn more about Nanopayments.
How Tachyon Uses Them
Tachyon exposes an x402-protected transaction relay endpoint. The client pays the requested relay cost from its Circle Gateway USDC balance, and Tachyon pays the destination-chain gas and submits the blockchain transaction. Learn more about the Tachyon relay API.
After a one-time USDC deposit into Gateway, the buyer signs each payment authorization offchain. Circle batches settlement, while Tachyon executes the requested blockchain transaction.
Learn more about the Circle buyer flow
Circle describes Nanopayments as supporting gas-free USDC payments down to $0.000001. The initial Gateway deposit is still an onchain transaction. The individual x402 payment authorizations after that deposit do not require a separate gas payment from the buyer.
How It Works
The integration combines three systems:
- Tachyon receives and relays the blockchain transaction.
- x402 negotiates payment through the HTTP
402 Payment Requiredflow. - Circle Gateway Nanopayments signs the USDC authorization and settles payments in batches.
The request flow is:
- Deposit USDC into the Circle Gateway Wallet contract.
- Call Tachyon's x402-protected
/api/submit-txendpoint. - Tachyon returns payment requirements when payment is needed.
GatewayClient.pay()signs the payment authorization offchain.- The client retries the request with the payment signature.
- Tachyon accepts the payment and submits the requested transaction.
- Circle Gateway settles the accumulated payment authorizations in batches.
The Circle payment authorization is gasless for the buyer, but the destination blockchain transaction still consumes gas. Tachyon pays for that execution and charges the corresponding cost through the x402 payment.
Prerequisites
- Node.js 18+
- An EVM private key
- USDC and native gas token on Base for the initial Gateway deposit
- Access to the Tachyon x402 transaction endpoint
GATEWAY_PRIVATE_KEY controls the wallet and its Gateway balance. Keep it in
a server-side environment variable or secure key-management system. Never
expose it in browser code or commit it to source control.
Step-by-Step Implementation
Install Dependencies
npm install @circle-fin/x402-batching viemInitialize Circle Gateway
import {
GatewayClient,
SupportedChainName,
} from "@circle-fin/x402-batching/client";
import { encodeFunctionData, parseAbi } from "viem";
const client = new GatewayClient({
chain: "base" as SupportedChainName,
privateKey: process.env.GATEWAY_PRIVATE_KEY as `0x${string}`,
});The configured chain is used for Gateway deposits, balance queries, and payments.
Fund the Gateway Balance
The Gateway balance must contain enough USDC to pay for the Tachyon request. Check the balance before depositing so the script does not deposit on every run:
const balances = await client.getBalances();
console.log(
`Gateway available: ${balances.gateway.formattedAvailable} USDC`
);
const minimumBalance = BigInt(100_000); // 0.1 USDC, 6 decimals
if (balances.gateway.available < minimumBalance) {
const deposit = await client.deposit("0.1");
console.log(
`Deposited ${deposit.formattedAmount} USDC: ${deposit.depositTxHash}`
);
}The deposit is an onchain transaction. Wait for it to confirm before relying on the updated Gateway balance.
Build the Tachyon Transaction
const callData = encodeFunctionData({
abi: parseAbi(["function sayHello(string message)"]),
functionName: "sayHello",
args: ["Hello from Tachyon!"],
});
const tx = {
chainId: 8453,
to: "0xA7A833e6641D7901F30EaD6f27d4Ee2C9bb670a7",
callData,
value: "0",
gasLimit: "100000",
label: process.env.TX_LABEL ?? "circle-gateway-nanopayment",
};This example calls sayHello("Hello from Tachyon!") on Base.
Pay and Submit
Call the Tachyon endpoint through GatewayClient.pay():
const baseUrl =
process.env.TACHYON_BASE_URL ?? "https://tachyon.rath.fi";
const url = new URL("/api/submit-tx", baseUrl).toString();
const result = await client.pay<SubmitTxResponse>(url, {
method: "POST",
body: tx,
});pay() handles the x402 negotiation, signs the Circle Gateway payment
authorization, and returns the Tachyon API response.
Read the Result
if (!result.data.success) {
throw new Error(
result.data.error?.message ?? "Tachyon submission failed"
);
}
console.log(`Tachyon tx id: ${result.data.data?.txId}`);
console.log(
`Estimated execution cost: $${result.data.data?.estimatedCostUSD}`
);
console.log(`Paid: ${result.formattedAmount} USDC`);
console.log(`Gateway settlement: ${result.transaction}`);The Tachyon txId identifies the relay task. The Gateway fields describe the
USDC payment authorization and settlement.
Complete Example
import {
GatewayClient,
SupportedChainName,
} from "@circle-fin/x402-batching/client";
import { encodeFunctionData, parseAbi } from "viem";
type SubmitTxResponse = {
success: boolean;
data?: {
txId: string;
estimatedCostUSD?: number;
x402Payment?: {
amount: string;
amountUsd: number;
network: string;
transaction: string;
};
};
error?: {
message: string;
};
};
function readEnv(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Missing environment variable: ${name}`);
}
return value;
}
async function main() {
const baseUrl =
process.env.TACHYON_BASE_URL ?? "https://tachyon.rath.fi";
const url = new URL("/api/submit-tx", baseUrl).toString();
const client = new GatewayClient({
chain: "base" as SupportedChainName,
privateKey: readEnv("GATEWAY_PRIVATE_KEY") as `0x${string}`,
});
let balances = await client.getBalances();
console.log(
`Gateway available: ${balances.gateway.formattedAvailable} USDC`
);
const minimumBalance = BigInt(100_000); // 0.1 USDC, 6 decimals
if (balances.gateway.available < minimumBalance) {
const deposit = await client.deposit("0.1");
console.log(
`Deposited ${deposit.formattedAmount} USDC: ${deposit.depositTxHash}`
);
balances = await client.getBalances();
console.log(
`Updated Gateway balance: ${balances.gateway.formattedAvailable} USDC`
);
}
const callData = encodeFunctionData({
abi: parseAbi(["function sayHello(string message)"]),
functionName: "sayHello",
args: ["Hello from Tachyon!"],
});
const tx = {
chainId: 8453,
to: "0xA7A833e6641D7901F30EaD6f27d4Ee2C9bb670a7",
callData,
value: "0",
gasLimit: "100000",
label: process.env.TX_LABEL ?? "circle-gateway-nanopayment",
};
const result = await client.pay<SubmitTxResponse>(url, {
method: "POST",
body: tx,
});
if (!result.data.success) {
throw new Error(
result.data.error?.message ?? "Tachyon submission failed"
);
}
console.log(`Tachyon tx id: ${result.data.data?.txId}`);
console.log(
`Estimated execution cost: $${result.data.data?.estimatedCostUSD}`
);
console.log(`Paid: ${result.formattedAmount} USDC`);
console.log(`Gateway settlement: ${result.transaction}`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});Why Use Tachyon with Circle Gateway Nanopayments?
USDC Payments for Transaction Relaying
Applications and AI agents can pay Tachyon transaction relay costs in USDC instead of maintaining a separate native-token payment flow for each API request.
Gasless Per-Request Authorization
After the initial deposit, each buyer payment is authorized with an offchain signature. There is no separate onchain payment transaction for every Tachyon request.
Batched Settlement
Circle Gateway aggregates signed authorizations and settles net positions in batches. This reduces the per-payment settlement overhead and supports high-frequency usage.
Agentic and Usage-Based Payments
The x402 flow is suitable for AI agents, machine-to-machine services, pay-per-request APIs, and other automated systems that need programmatic payments without subscriptions or manual checkout.
Key Considerations
- The Gateway deposit requires USDC and native gas on the selected chain.
- Maintain enough available Gateway balance for the expected Tachyon cost.
- Validate the Tachyon response before treating a request as submitted.
- Circle Gateway settlement may happen after Tachyon accepts the signed payment authorization.
- Confirm current Circle-supported networks before selecting a production chain.
Related Tachyon Resources
Non-Custodial Transactions
Execute non-custodial transactions on Tachyon using quote and submit-signed-tx endpoints with NEAR Chain Signatures for accurate cost estimates and secure execution.
Token Swap with Permit API
Perform token swaps using custodial wallets by leveraging EIP-712 signatures and ERC-20 permit functionality.