TypeScript reverse proxy for paid HTTP APIs. This version uses the npm TypeScript x402 SDK packages only:
@bankofai/x402-core@1.0.1@bankofai/x402-evm@1.0.1@bankofai/x402-tron@1.0.1
Payment requirements support logical scheme=exact and TRON
scheme=exact_gasfree. The transfer method is selected by the registered
asset: Base USDC uses EIP-3009 metadata, while BSC/TRON USDT uses Permit2.
GasFree uses the TRON GasFree relayer flow without Permit2 metadata.
npm install
npm run buildAfter installing the npm package globally, use the binary directly:
npm install -g @bankofai/x402-gateway@1.0.2
x402-gateway --helpStart from a single provider file:
x402-gateway --provider /path/to/provider.yml --host 127.0.0.1 --port 4020Start from a runtime Provider directory:
x402-gateway --providers /path/to/providers --host 127.0.0.1 --port 4020Validate provider files without starting the server:
x402-gateway check --providers /path/to/providers
x402-gateway check --provider /path/to/provider.yml --jsoncheck validates provider YAML syntax, required fields, environment expansion,
network aliases, endpoint shape, and duplicate provider names. It does not call
upstream APIs, facilitator services, RPC endpoints, recipient addresses, or the
full payment path.
Run from source during development:
npm run dev -- --providers /path/to/providers --host 127.0.0.1 --port 4020Health check:
curl http://127.0.0.1:4020/__402/healthPaid provider path:
curl -i http://127.0.0.1:4020/providers/defillama-tvl-base-sepolia/protocolsIf the endpoint has metering, the gateway returns 402 Payment Required with a
PAYMENT-REQUIRED header. After the client retries with PAYMENT-SIGNATURE,
the gateway verifies and settles with the facilitator, then forwards to the
configured upstream.
x402-gateway start --providers <dir> [options]
x402-gateway --providers <dir> [options]
x402-gateway check --providers <dir>
x402-gateway check --provider <file>
Options:
--provider <file>: load one provider YAML file.--providers <dir>: recursively loadprovider.yml/provider.yaml.--providerand--providersare mutually exclusive.--host <host>: bind host. The CLI default is127.0.0.1; Docker passes0.0.0.0.--port <port>: bind port, default8080.--json: machine-readable startup/check/error output.--quiet: suppress startup, shutdown, and successfulcheckoutput.--debug: include stack traces for startup errors.--help,--version: inspect usage and installed version.
Startup prints human-readable URLs by default:
x402-gateway listening on http://127.0.0.1:4020
providers: 1 loaded
health: http://127.0.0.1:4020/__402/health
ready: http://127.0.0.1:4020/__402/ready
With --json, startup output includes source, host, port, count,
providers, health, and ready for deployment scripts. CLI errors also
honor --json, including argument parsing errors such as unknown options.
Admin endpoints such as /__402/providers, /__402/endpoints, and /metrics
are protected by default. Set X402_GATEWAY_ADMIN_TOKEN in deployed
environments and call them with Authorization: Bearer <token>. For a
deliberately public test deployment, set X402_GATEWAY_ADMIN_ALLOW_PUBLIC=true.
Provider files stay in YAML:
name: example-provider
forward_url: ${X402_PROVIDER_FORWARD_URL}
routing:
auth:
method: header
key: Authorization
prefix: "Bearer "
value_from_env: X402_PROVIDER_API_TOKEN
operator:
network: ${X402_PROVIDER_NETWORK}
currencies:
usd: ["USDC"]
recipient: ${X402_PROVIDER_RECIPIENT}
scheme: exact
protocol: exact
facilitator_url: ${X402_FACILITATOR_URL}
facilitator_api_key_env: X402_FACILITATOR_API_KEY
valid_for_seconds: 300
endpoints:
- method: GET
path: /v1/ping
request:
query:
symbol:
required: true
type: string
min_length: 1
response:
json:
field: code
equals: 1
metering:
dimensions:
- tiers:
- price_usd: 0.002scheme: exact describes settlement semantics, not a universal token
authorization mechanism. Registered token metadata selects EIP-3009 or
Permit2. To force Permit2 for a supported token, use
asset_transfer_method: permit2. Historical protocol aliases such as
exact_permit and exact_permit2 are rejected with a migration error instead
of silently changing transfer methods. For GasFree, set both scheme and
protocol to exact_gasfree; the facilitator must support GasFree for the
selected TRON network and token.
Paid endpoints can declare required query parameters, headers, and JSON body
fields under request. Validation runs before the gateway returns a 402, so a
known-invalid request is never verified or settled. Supported field checks are
required, type, format, min_length, max_length, and enum. Supported
formats are evm_address and evm_address_list.
APIs that encode business failures inside HTTP 200 JSON responses can declare
response.json.field and response.json.equals. A mismatch is treated as an
upstream failure and is not counted as a successful delivery.
Non-CAIP TRON aliases are rejected. Provider files must use canonical TRON CAIP-2 IDs.
EVM convenience aliases accepted:
bsc-mainnet->eip155:56bsc-testnet->eip155:97base-mainnet->eip155:8453base-sepolia->eip155:84532
X402_GATEWAY_PROVIDERS_DIR=providers
X402_GATEWAY_HOST=127.0.0.1
PORT=8080
X402_GATEWAY_ADMIN_TOKEN=<admin-token>
X402_GATEWAY_PUBLIC_BASE_URL=https://gateway.example.com
X402_GATEWAY_BUILD_COMMIT=<git-sha>
X402_GATEWAY_MAX_BODY_BYTES=1000000
X402_GATEWAY_MAX_RESPONSE_BYTES=20000000
X402_GATEWAY_FACILITATOR_TIMEOUT_MS=10000
X402_GATEWAY_UPSTREAM_TIMEOUT_MS=30000
X402_GATEWAY_MAX_CONCURRENT_REQUESTS=100
X402_GATEWAY_RATE_LIMIT_PER_MINUTE=300
X402_GATEWAY_ALLOW_INSECURE_HTTP=false
X402_FACILITATOR_URL=https://facilitator.bankofai.io
X402_FACILITATOR_API_KEY=<facilitator-api-key>Provider YAML may also use operator.facilitator_api_key_env: X402_FACILITATOR_API_KEY so deployments can inject the facilitator API key via
environment variable without storing it in the mounted provider file.
When facilitator_api_key_env is configured, that named variable is required;
check and start fail instead of silently contacting the facilitator without
authentication.
X402_GATEWAY_PUBLIC_BASE_URL must be the externally reachable gateway origin.
It makes the challenge resource.url absolute, which is required when the
container's internal host or request path is not the public payment URL.
docker compose up --build uses the current checkout and
pull_policy: build; it does not pull the mutable remote test image.
Set X402_GATEWAY_PROVIDERS_HOST_DIR to a runtime Provider directory. Compose
mounts it read-only at /app/providers. The fallback ./providers directory
is Git-ignored:
X402_GATEWAY_PROVIDERS_HOST_DIR=/path/to/providers docker compose up --buildRelease deployments should use an immutable semantic version or image digest. The container runs the same CLI binary:
docker run --rm -p 4020:8080 \
-v "$PWD/providers:/app/providers:ro" \
-e X402_GATEWAY_ADMIN_TOKEN=<admin-token> \
-e X402_FACILITATOR_API_KEY=<facilitator-api-key> \
bankofai/x402-gateway@<sha256-digest>The Docker command binds 0.0.0.0:8080 explicitly; local CLI runs default to
127.0.0.1 unless --host or X402_GATEWAY_HOST is set.
The protected /metrics endpoint separates request, settlement, and delivery
semantics:
x402_gateway_http_requests_total: all HTTP traffic, including admin paths.x402_gateway_provider_requests_total: requests matched to provider routes.x402_gateway_settlements_total: successful payment settlements.x402_gateway_deliveries_total: settled requests delivered from upstream.x402_gateway_post_settlement_failures_total: failures after settlement.
x402_gateway_post_settlement_failures_total is a subset of
x402_gateway_upstream_failures_total; one post-settlement upstream failure
increments both counters intentionally.
For compatibility with existing dashboards, the endpoint also emits
x402_gateway_requests_total and x402_gateway_paid_requests_total as
deprecated aliases for HTTP requests and successful settlements respectively.
These counters do not claim that a settlement implies successful business delivery.