Knox is a Bun-based CLI payment client for paid HTTP APIs that support 402 Payment Required with:
- x402
- MPP
It provides a curl-like request command, a local account store, and a plugin system with hooks throughout the request lifecycle.
npm install -g knox-wallet
knox --help# account management
knox account create --force
knox account import --private-key <hex> --force
knox account status
# request execution
knox request https://httpbin.org/get
knox request --protocol x402 "https://lorem.steer.fun/generate?count=2&units=paragraphs&format=plain"
knox request --protocol mpp "https://lorem.steer.fun/generate?count=2&units=paragraphs&format=plain"
# dry run (no signature, no payment)
knox --dry-run request --protocol x402 "https://lorem.steer.fun/generate?count=2&units=paragraphs&format=plain"
# transactions and plugins
knox tx list
knox tx show <id>
knox plugins list
knox plugins setup <plugin-name>--protocol auto|x402|mpp--dry-run--no-plugins
- Knox supports one local account for now.
- Running
account createoraccount importreplaces the existing account. - If an account already exists, use
--forcewithaccount createandaccount importto confirm replacement.
~/.knox/plugins/*.{ts,js,mjs,cjs}.knox/plugins/*.{ts,js,mjs,cjs}
Plugin module shape:
export type AccountPlugin = {
name: string;
setup?: (event: PluginSetupEvent) => Promise<PluginSetupResult | void>;
beforeTransaction?: (event: BeforeTransactionEvent) => Promise<BeforeTransactionResult | void>;
beforeSign?: (event: BeforeSignEvent) => Promise<BeforeSignResult | void>;
afterTransaction?: (event: AfterTransactionEvent) => Promise<void>;
accountStatus?: (event: AccountStatusEvent) => Promise<AccountStatusResult | void>;
};Event contracts:
type BeforeTransactionResult =
| { action: "continue" }
| { action: "abort"; reason: string };
type BeforeSignResult =
| { action: "continue"; intentOverride?: Partial<PaymentIntent> }
| { action: "abort"; reason: string };
type AccountStatusResult = { output: string };
type PluginSetupResult = { output?: string };
type PluginSetupEvent = {
account: {
address: `0x${string}`;
source: string;
} | null;
};Behavior:
beforeTransaction: fail-closed, can block payment.beforeSign: fail-closed, can block payment and optionally mutatePaymentIntentviaintentOverride.afterTransaction: fail-open, errors are logged.accountStatus: runs duringknox account status; output is rendered as multiline text under plugin name.setup: runs when invokingknox plugins setup <plugin-name>and receives current account context (ornull).
Minimal plugin example:
export default {
name: "status-note",
async accountStatus() {
return {
output: "All systems nominal\nReady to pay",
};
},
};Example plugins:
examples/plugins/confirm-before-sign.ts: interactive blocking confirmation before signing.examples/plugins/account-status-balances.ts: reports Base USDC and Tempo token balances inknox account status.
To activate an example plugin, copy it to one of the plugin directories:
mkdir -p .knox/plugins
cp examples/plugins/confirm-before-sign.ts .knox/plugins/
cp examples/plugins/account-status-balances.ts .knox/plugins/bun install
bun run typecheckKnox uses Changesets with a manually triggered GitHub Actions workflow.
- Add a changeset in your PR:
bun run changeset- Merge the PR into
main. - In GitHub, run the
Releaseworkflow manually from Actions. - If there are unpublished changesets, the workflow creates or updates a version PR (
chore: version packages). - Merge the version PR, then run the
Releaseworkflow again to publish.
Trusted publishing is configured for npm via GitHub OIDC, so no long-lived NPM_TOKEN is required for normal releases.