Wrap the standard openai.OpenAI client with per-chain private keys.
When the server responds with HTTP 402, the library automatically signs and retries the request — zero code changes needed.
Supplying evm or svm registers both exact and upto. aptos, avm, stellar, hedera, near, xrpl, tvm, keeta, and concordium register exact only. Default spend controls from @x402/core cap each payment at $1 of a recognized default asset.
bun add @qntx/openai @x402/evm viem # EVM (Ethereum / Base / …)
bun add @qntx/openai @x402/svm @solana/kit @scure/base # Solana
bun add @qntx/openai @x402/aptos # Aptos
bun add @qntx/openai @x402/avm # Algorand (AVM)
bun add @qntx/openai @x402/stellar # Stellar
bun add @qntx/openai @x402/hedera # Hedera
bun add @qntx/openai @x402/near # NEAR
bun add @qntx/openai @x402/xrpl xrpl # XRPL
bun add @qntx/openai @x402/tvm @ton/crypto # TVM (TON)
bun add @qntx/openai @x402/keeta @keetanetwork/keetanet-client # Keeta
bun add @qntx/openai @x402/concordium @concordium/web-sdk # Concordiumimport { X402OpenAI } from "@qntx/openai";
const client = new X402OpenAI({
evm: "0x…",
});
const res = await client.chat.completions.create({
model: "openai/gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(res.choices[0]?.message.content);Pass svm: "base58…" instead of evm to pay on Solana — the rest of the API is identical. The same constructor accepts aptos, avm, stellar, hedera, near, xrpl, tvm, keeta, and concordium.
const stream = await client.chat.completions.create({
model: "openai/gpt-4o-mini",
messages: [{ role: "user", content: "Explain x402" }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) process.stdout.write(content);
}const client = new X402OpenAI({
evm: "0x…",
svm: "base58…",
aptos: "0x…",
avm: "base64…",
stellar: "S…",
hedera: { accountId: "0.0.N", privateKey: "0x…" },
near: { accountId: "alice.near", secretKey: "ed25519:…" },
xrpl: "sEd…",
tvm: "hex-or-base64…",
keeta: process.env.KEETA_SEED,
concordium: { privateKey: "hex…", address: "base58…" },
});The protocol selects the right chain automatically based on the server's payment requirements.
| Option | Key material |
|---|---|
evm |
0x hex secp256k1 |
svm |
base58 64-byte secret |
aptos |
hex or AIP-80 Ed25519 (ed25519-priv-0x…) |
avm |
base64 64-byte secret (32-byte seed + 32-byte pubkey) |
stellar |
Stellar S… secret seed |
hedera |
ECDSA hex/DER plus 0.0.N account id |
near |
ed25519:… / secp256k1:… plus account id |
xrpl |
XRPL family seed (not BIP-39) |
tvm |
hex/base64 32-byte seed or 64-byte secret |
keeta |
generateRandomSeed({ asString: true }) output, not BIP-39 |
concordium |
hex Ed25519 plus base58 address |
Bare evm / svm / aptos / avm / stellar / tvm strings become { privateKey }. Bare xrpl / keeta strings become { seed }. hedera, near, and concordium have no string overload. Empty strings throw. Keeta 12/24-word BIP-39 strings throw.
These families register exact only (upto is not implemented in @x402/* for them).
- Aptos (
aptos:*):createClientSignerfrom@x402/aptos. OptionalrpcUrl. Optional 402extra.feePayerenables a sponsored tx. - AVM (
algorand:*):toClientAvmSignerfrom@x402/avm. OptionalalgodUrl/algodToken. Do not pass a prebuilt Algorand client here — use thex402Clienthatch. Optional 402extra.feePayerfor a gasless group. - Stellar (
stellar:*):createEd25519Signerfrom@x402/stellar. Defaultnetworkisstellar:pubnet(the official factory defaults tostellar:testnet). Passnetwork: "stellar:testnet"for testnet. OptionalrpcUrlis a Soroban RPC endpoint (required for pubnet payments). The 402 must setextra.areFeesSponsored === trueor the scheme throws.
These families also register exact only, on a concrete CAIP-2 (not a wildcard). Default networks are mainnet.
- Hedera (
hedera:mainnetby default, orhedera:testnet):{ accountId, privateKey, network?, nodeUrl? }. No string overload. The 402 must setextra.feePayer. Native HBAR (asset: "0.0.0") is not a default asset — passspendControls.allowedAssetsto allow it. - NEAR (
near:mainnetby default, ornear:testnet):{ accountId, secretKey, network?, rpcUrl? }. No string overload. OptionalrpcUrlis mapped to{ [network]: rpcUrl }. - XRPL (
xrpl:0by default, orxrpl:1): family seed, or{ seed, network?, wsUrl? }. OptionalwsUrlis mapped to{ [network]: wsUrl }. The 402 must setextra.areFeesSponsored === false(the payer pays the XRPL fee). Default asset is RLUSD; native XRP is not allowed unless you opt in:
new X402OpenAI({
xrpl: { seed, network: "xrpl:0" },
spendControls: {
allowedAssets: [{ network: "xrpl:*", asset: "XRP" }],
},
});These families also register exact only. TVM uses a concrete CAIP-2; Keeta and Concordium use wildcards.
- TVM (
tvm:-239by default, ortvm:-3): hex/base64 32-byte seed or 64-byte secret, or{ privateKey, network?, provider?, apiKey?, providerBaseUrl? }. The 402 must setextra.areFeesSponsored === true. Do not registertvm:*— the signer is bound to one network. - Keeta (
keeta:*):generateRandomSeed({ asString: true })output, or{ seed }. Not a BIP-39 mnemonic (12/24-word strings throw). This package never callsseedFromPassphrase. - Concordium (
ccd:*):{ privateKey, address, grpcUrl?, useTls? }. No string overload (addressis required). OfficialuseTlsdefault istrue. The 402 must setextra.feePayer. Default asset is USDR; native CCD is not allowed unless you opt in:
new X402OpenAI({
concordium: { privateKey, address },
spendControls: {
allowedAssets: [{ network: "ccd:*", asset: "CCD" }],
},
});Long-lived TVM and Keeta clients hold HTTP / UserClient handles. Call await client.close() (or await using) when finished. close() before the first request is a no-op. Fetch after close() throws X402OpenAI is closed and does not rebuild.
new x402Client() already allows only default (USD-pegged) assets and caps each payment at $1. This package does not change that default.
Pass spendControls to raise the cap, allow extra assets, or disable controls:
const client = new X402OpenAI({
evm: "0x…",
spendControls: { maxAmountPerPayment: "$5" },
});- Omit
spendControlsto keep the official$1+ default-asset allowlist. spendControls: falsedisables allowlist and caps.- Gateway prices above
$1require the caller to raisemaxAmountPerPayment.
evm registers ExactEvmScheme and UptoEvmScheme on eip155:*. svm registers ExactSvmScheme and UptoSvmScheme on solana:*. No extra flag; the gateway is not probed.
- EVM
upto: Permit2 (permitWitnessTransferFrom). The 402 must includeextra.facilitatorAddress. Pass{ rpcUrl }onevmto enable official EIP-2612 / ERC-20 approval sponsoring. - SVM
upto: payment-channelopenthat escrows the full authorized ceiling until settle/close. The 402 must includeextra.feePayerandextra.receiverAuthorizer. - The 402
amountis the authorized maximum. The client signs that max; it does not sign a smaller amount. The server chooses the actual charge (<=max) at settle. If the ceiling exceeds spend controls, payment creation throws.
import { preferScheme, X402OpenAI } from "@qntx/openai";
const client = new X402OpenAI({
evm: "0x…",
policies: [preferScheme("upto")],
});Use policies to prefer a chain or scheme when multiple options remain after spend controls. Policies do not cap spend.
import { X402OpenAI, preferNetwork, preferScheme } from "@qntx/openai";
const client = new X402OpenAI({
evm: "0x…",
svm: "base58…",
policies: [
preferNetwork("eip155:8453"), // Prefer Base mainnet
preferScheme("upto"),
],
});If nothing matches, all remaining options pass through.
Drop-in replacement for openai.OpenAI. Provide at least one of evm, svm, aptos, avm, stellar, hedera, near, xrpl, tvm, keeta, concordium, or x402Client:
| Parameter | Type | Description |
|---|---|---|
evm |
`0x${string}` or EvmConfig |
EVM secp256k1 private key (0x hex). Registers exact and upto. |
svm |
string or SvmConfig |
Solana base58 secret key. Registers exact and upto. |
aptos |
string or AptosConfig |
Aptos hex or AIP-80 Ed25519 key. Registers exact. |
avm |
string or AvmConfig |
Algorand base64 64-byte secret. Registers exact. |
stellar |
string or StellarConfig |
Stellar S… secret. Registers exact. Default network stellar:pubnet. |
hedera |
HederaConfig |
Hedera account id + ECDSA key. Registers exact on hedera:mainnet by default. |
near |
NearConfig |
NEAR account id + secret key. Registers exact on near:mainnet by default. |
xrpl |
string or XrplConfig |
XRPL family seed. Registers exact on xrpl:0 by default. |
tvm |
string or TvmConfig |
TON seed/secret. Registers exact on tvm:-239 by default. |
keeta |
string or KeetaConfig |
Keeta seed (not BIP-39). Registers exact on keeta:*. |
concordium |
ConcordiumConfig |
Concordium key + address. Registers exact on ccd:*. |
spendControls |
SpendControls or false |
Official spend controls. Omit for $1 + default assets. |
policies |
PaymentPolicy[] |
Preference policies (preferNetwork / preferScheme). |
paymentRequirementsSelector |
SelectPaymentRequirements |
Picks among remaining requirements after spend controls and policies. |
x402Client |
x402Client |
Pre-configured x402 client (exclusive with keys, spendControls, policies, paymentRequirementsSelector) |
| Type | Fields | Notes |
|---|---|---|
EvmConfig, SvmConfig, AptosConfig |
{ privateKey, rpcUrl? } |
|
AvmConfig |
{ privateKey, algodUrl?, algodToken? } |
|
StellarConfig |
{ privateKey, network?, rpcUrl? } |
rpcUrl is required on pubnet |
HederaConfig |
{ accountId, privateKey, network?, nodeUrl? } |
|
NearConfig |
{ accountId, secretKey, network?, rpcUrl? } |
rpcUrl → { [network]: rpcUrl } |
XrplConfig |
{ seed, network?, wsUrl? } |
wsUrl → { [network]: wsUrl } |
TvmConfig |
{ privateKey, network?, provider?, apiKey?, providerBaseUrl? } |
|
KeetaConfig |
{ seed } |
|
ConcordiumConfig |
{ privateKey, address, grpcUrl?, useTls? } |
Empty keys throw.
close(): Promise<void> (also [Symbol.asyncDispose]) releases Keeta/TVM handles. Close before the first request is a no-op. Fetch after close throws X402OpenAI is closed and does not rebuild.
SpendControls is Exclude<NonNullable<x402ClientConfig["spendControls"]>, false> from @x402/fetch.
All standard OpenAI options (baseURL, timeout, maxRetries, …) are forwarded. Default baseURL: https://llm.qntx.org/v1.
| Option | Chain | Install extras |
|---|---|---|
evm |
EVM | @x402/evm viem |
svm |
Solana | @x402/svm @solana/kit @scure/base |
aptos |
Aptos | @x402/aptos |
avm |
Algorand | @x402/avm |
stellar |
Stellar | @x402/stellar |
hedera |
Hedera | @x402/hedera |
near |
NEAR | @x402/near |
xrpl |
XRPL | @x402/xrpl xrpl |
tvm |
TVM | @x402/tvm @ton/crypto |
keeta |
Keeta | @x402/keeta @keetanetwork/keetanet-client |
concordium |
Concordium | @x402/concordium @concordium/web-sdk |
See the examples/ directory. Each script is self-contained:
EVM_PRIVATE_KEY="0x…" bun examples/chat-evm.ts
SOLANA_PRIVATE_KEY="base58…" bun examples/chat-svm.ts
EVM_PRIVATE_KEY="0x…" bun examples/streaming-evm.ts
EVM_PRIVATE_KEY="0x…" bun examples/chat-upto.ts
EVM_PRIVATE_KEY="0x…" bun examples/chat-policy.ts
EVM_PRIVATE_KEY="0x…" bun examples/chat-evm-policy.ts
EVM_PRIVATE_KEY="0x…" SOLANA_PRIVATE_KEY="base58…" bun examples/chat-multichain-policy.tsThis project is licensed under the MIT License.