npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

stellar-agent-pay-cli

v0.1.0

Published

CLI that pays an x402-gated URL from the terminal: 402 -> pay -> unlock, for agents and shell scripts

Readme

stellar-agent-pay-cli

Pay an x402-gated URL from the terminal. One command does the whole loop: 402 → pay → unlock.

stellar-agent-pay https://api.example.com/weather

Any agent or shell script that can run a binary can now pay for API access. No custody logic, no manual transaction building.

Built for the GrantFox Stellar Builder Summit SP 2026 bounty, sub-lane 3B (CLI Plugins for Agents). It pairs with stellar-x402-paywall-kit (sub-lane 3A): gate a route with the kit, pay it with this CLI.

Contents: Install · Setup · Usage · Safety · MCP tool · Demo · Testnet runbook · Testing · Proof of work · Design notes and known limits · Troubleshooting

Install

Requires Node.js 20 or newer.

npm install -g stellar-agent-pay-cli

Not on npm yet. Until it is published, install from source:

git clone https://github.com/StevenMolina22/stellar-agent-pay-cli.git
cd stellar-agent-pay-cli && npm install && npm link

Setup

Two environment variables:

export STELLAR_NETWORK=stellar:testnet
export STELLAR_SECRET_KEY=S...   # needs a funded USDC balance, see the testnet runbook

Both can be overridden per call with --network and --secret.

Usage

# Pay and print the unlocked response body
stellar-agent-pay https://api.example.com/weather

# See what it would cost, without paying
stellar-agent-pay https://api.example.com/weather --dry-run

# Refuse to pay more than $0.01
stellar-agent-pay https://api.example.com/weather --max-price 0.01

# POST with a body
stellar-agent-pay https://api.example.com/report --method POST --data '{"city":"BA"}'

# Extra header, plus a JSON envelope on stdout
stellar-agent-pay https://api.example.com/weather --header "X-Trace: 1" --json

# Append an audit line per attempt
stellar-agent-pay https://api.example.com/weather --log-file ~/.stellar-agent-pay/payments.jsonl

Options

| Flag | What it does | |---|---| | --method <verb> | HTTP method. Default GET. | | --data <json> | Request body, sent as JSON. | | --header "K: V" | Extra request header. Repeatable. | | --max-price <usd> | Refuse to pay more than this. Fails closed. | | --allow-recipient <G...> | Only pay these recipients. Repeatable. Fails closed. | | --block-recipient <G...> | Never pay these recipients. Repeatable. Wins over allow. | | --dry-run | Show the price and requirements, pay nothing. | | --network <id> | CAIP-2 network id. Default STELLAR_NETWORK or stellar:testnet. | | --secret <S...> | Stellar secret key. Default STELLAR_SECRET_KEY. | | --json | Wrap stdout as { status, body, settlement }. | | --log-file <path> | Append one JSONL line per attempt (timestamp, url, status, amount, tx). | | -h, --help | Show help. |

Output and exit codes

The response body goes to stdout. Settlement info (amount, tx hash, network) goes to stderr, so piping stays clean:

stellar-agent-pay https://api.example.com/weather | jq .temp

| Code | Meaning | |---|---| | 0 | Success (2xx response after payment, or a --dry-run that needed no payment) | | 1 | Config error: missing URL, missing secret key, malformed flag | | 2 | Payment or HTTP error, including "every offer exceeded --max-price" |

Safety

x402 lets the server name its price per request. For an unattended agent that is a blank check, so this CLI ships three guardrails. All of them are checked before anything is signed, so a refusal costs no transaction and no fee.

  • --max-price <usd> caps what a single call may pay. Offers above the cap are filtered out; if nothing survives, the request fails instead of paying whatever was asked.
  • --allow-recipient / --block-recipient filter on the server's payTo address. A block-list entry always wins, so you cannot allow-list your way past a known-bad address by mistake.
  • STELLAR_AGENT_PAY_SESSION_CAP_USD caps cumulative spend across a whole MCP session. The one-shot CLI cannot do this (each run is a fresh process); the long-lived MCP server can.

Why the checks sit where they do, and what they do not cover, is in Design notes and known limits.

MCP tool

For MCP-aware agents (Claude Code and similar), the same logic is exposed as three tools instead of shelling out to the CLI.

| Tool | Purpose | Parameters | |---|---|---| | peek_paywall | Inspect the price without paying | url (required) | | pay_url | Pay and return the unlocked resource | url (required), method (default GET), maxPriceUsd (e.g. "0.01") | | session_status | Report spend so far and remaining budget | none |

npm install stellar-agent-pay-cli @modelcontextprotocol/sdk zod
{
  "mcpServers": {
    "stellar-agent-pay": {
      "command": "stellar-agent-pay-mcp",
      "env": {
        "STELLAR_NETWORK": "stellar:testnet",
        "STELLAR_SECRET_KEY": "S...",
        "STELLAR_AGENT_PAY_SESSION_CAP_USD": "1.00",
        "STELLAR_AGENT_PAY_BLOCK_RECIPIENTS": "GBADACTOR1...,GBADACTOR2..."
      }
    }
  }
}

STELLAR_AGENT_PAY_ALLOW_RECIPIENTS and STELLAR_AGENT_PAY_BLOCK_RECIPIENTS (comma-separated G... addresses) apply to every pay_url call. They are set in the environment on purpose, not passed as tool parameters: the agent picks what to buy, the operator decides which guardrails apply.

Demo: pair it with the paywall kit

# Terminal 1: gate a route
cd stellar-x402-paywall-kit/examples/express-app && npm start

# Terminal 2: pay it
stellar-agent-pay http://localhost:3001/weather

Testnet runbook

  1. Generate a payer keypair and fund it with XLM:
    node -e "const {Keypair}=require('@stellar/stellar-sdk'); const k=Keypair.random(); console.log(k.publicKey(), k.secret())"
    curl "https://friendbot.stellar.org?addr=<G...>"
  2. Add a USDC trustline. stellar-x402-paywall-kit/scripts/setup-testnet.mjs sets up both sides of the demo.
  3. Fund it with testnet USDC at faucet.circle.com (Stellar testnet, web only, cannot be scripted).
  4. Export the keys from step 1:
    export STELLAR_SECRET_KEY=S...
    export STELLAR_NETWORK=stellar:testnet

Testing

npm test   # 55 offline tests: no network, no facilitator, no funded account

test/e2e.test.js adds 5 live tests that stand up a real paywall with the sibling kit and pay it through this package's own payUrl, against the live OZ Channels testnet facilitator. They cover the happy path, a --max-price refusal, a session-cap refusal, and the amount actually charged. They need the sibling repo checked out alongside this one plus a funded testnet payer:

OZ_API_KEY=... STELLAR_RECIPIENT=G... STELLAR_SECRET_KEY=S... npm test   # 60/60

Without those, the 5 live tests skip and the suite stays green, so npm test never fails for someone who has neither.

The live tests live here rather than in the seller kit because the buyer is what they exercise. An earlier arrangement where the kit owned the only live test meant that test rebuilt its own x402 client by hand and never touched this package's code.

Proof of work

Real payments on Stellar testnet, made by this CLI against the sibling repo's example server. Not mocked, not simulated. Verify any of them on Stellar Expert:

| tx hash | command | |---|---| | d8adef29...ee7e14fe | stellar-agent-pay http://localhost:3001/weather | | 4b0524e7...cdab979b83 | stellar-agent-pay http://localhost:3001/weather --max-price 0.01 | | 3ee14d47...9fed611 | stellar-agent-pay http://localhost:3001/weather/premium | | bd0f08a6...27018d576 | stellar-agent-pay http://localhost:3001/weather --allow-recipient G... | | c5917913...e6f06cd8 | stellar-agent-pay http://localhost:3002/catalog --max-price 0.01 | | 8c2eca1e...c55d3333b | stellar-agent-pay http://localhost:3002/reports/3 --max-price 0.01 |

Design notes and known limits

Where the cap is enforced. The session cap runs on the x402 client's onBeforePaymentCreation hook (src/spendGuard.js), which fires after the client picks the offer it will pay and before the scheme signs anything. That is the only point where the price is known for certain. Fetching a price separately and then paying means two independent negotiations that can disagree about which offer is being bought, and accepts has no defined price ordering that would make the first one safe to assume. Concurrent MCP tool calls are serialized (src/sessionCap.js) so two payments cannot both pass the check before either is recorded.

This is an app-level approximation, not an on-chain guarantee. For a session budget with a real on-chain guarantee (pre-authorized deposit, cumulative commitments, one settlement), that is what MPP Channel mode is for rather than x402.

Recipient lists are the same guardrail shape as a contract allow-list on an on-chain policy signer, applied at the app level because x402 on Stellar does not ship one yet. The design thinking comes from ArkivGate, a policy gateway for paid AI-agent runtimes the author built independently. It was reimplemented here for Stellar's client-side PaymentPolicy API, not ported.

Replay and double-grant on the seller side. A signed x402 payment auth entry is valid until its max_ledger expiry, which bounds how long it is valid, not whether it has already been redeemed. Research on x402 deployments found resource servers that grant access repeatedly for a single settlement (Five Attacks on x402, arXiv:2605.11781). This CLI is the buyer side and does not control that. If you are building the seller, see the security note in the paywall kit.

A settled payment does not tell you what it cost. A live PAYMENT-RESPONSE from OZ Channels decodes to {success, payer, transaction, network} with no amount field, pinned by a live test in test/e2e.test.js so it fails loudly if that changes. Anything reporting settlement.amount records undefined on every payment, which is what this CLI's own audit log did until that test caught it. The price is only reliably known from the offer the client selected, so payUrl returns amountPaid from there.

Facilitator settle dedup is unverified for Stellar. Whether OZ Channels' /settle deduplicates a retried submission of the same auth entry is not documented anywhere we could find for the Stellar scheme. That is why the retry in src/resilientFetch.js is scoped to the transport layer only (a dropped connection mid-request) and never re-runs the payment flow. Retrying a delivery and signing a second payment are different things.

Dependency pinning. @x402/* is pinned to exact 2.20.0, not a floating ^ range. GHSA-3j63-5h8p-gf7c affected the older x402/x402-express/x402-hono/x402-next v1 packages, and GHSA-qr2g-p6q7-w82m hit @x402/svm facilitators rather than Stellar's. Neither applies here directly, but both show this protocol has had real facilitator-side vulnerabilities. Pin and watch advisories.

Troubleshooting

Config error: ... (exit 1) means a missing URL, a missing secret key, or a malformed flag. Check STELLAR_SECRET_KEY is exported.

Payment fails with an insufficient balance or trustline error. The payer account needs both a USDC trustline and a funded USDC balance. Walk through the testnet runbook again; the Circle faucet step is the one most often missed.

Every offer exceeded --max-price (exit 2) is working as intended. Run with --dry-run to see what the server is actually asking.

Crash on exit with Assertion failed: !(handle->flags & UV_HANDLE_CLOSING) (Windows). A real bug, already fixed. Calling process.exit() right after creating the Ed25519 signer could race a pending libuv handle. The fix uses process.exitCode and lets the event loop drain. If you see it, update.

License

MIT