AgentScore Pay; one CLI for agent payments across the ecosystem. Pay any 402/MPP merchant from a single shell command, natively across x402 (Base) and MPP (Tempo, Solana), with structured hints to compatible clients for rails we don't fund directly (Stripe SPT via link-cli, other x402 networks).
Closes the UX gap for shell-tool LLM agents (Claude Code, Cursor, ChatGPT with Bash) that want to pay protocol-gated endpoints. Mirrors the ergonomics of tempo request for MPP — one shell command, body preserved, agent never sees a private key on the wire. Built and maintained by AgentScore — works with every 402-gated merchant in the ecosystem, AgentScore-gated or not. Pay does not contact AgentScore APIs unless the merchant's 402 challenge requires AgentScore identity.
# Run directly (no global install required)
npx @agent-score/pay --help
# Or install globally
npm i -g @agent-score/pay
agentscore-pay --help
# Or via the install script (auto-detects npm vs native binary)
curl -fsSL https://raw.githubusercontent.com/agentscore/pay/main/install.sh | sh
# Or via Homebrew
brew install agentscore/tap/agentscore-payRequires Node 20+ for the npm path. Native single-file binaries (no Node required) are attached to every GitHub Release.
# 1. One-shot init — encrypted keystores on every chain, derived from a single BIP-39 mnemonic
agentscore-pay init
# 2. Fund one of them (prints receive QR + polls balance)
agentscore-pay fund --chain base --amount 10
# 3. Pay — rail auto-selected from the single funded wallet
agentscore-pay pay POST https://agents.martinestate.com/purchase \
-H 'Content-Type: application/json' \
-d '{"product_id":"cabernet-sauvignon-2021","quantity":1,"email":"a@b.co","shipping":{...}}' \
--max-spend 250If multiple wallets are funded, specify the rail (or set preferred_chains in config):
agentscore-pay pay POST https://merchant.example/api --chain tempo -d '...' --max-spend 5For LLM tool-loop agents, run agentscore-pay agent-guide (add --json for parseable output) — it prints the structured how-to: golden path (init → discover → balance → check → dry-run → pay), testnet path, funding, auxiliary commands (unlock, limits, whoami, history), pitfalls, and exit-code branching. The same notes also surface in agentscore-pay <command> --help for check and pay.
Every command emits structured data. Choose your format:
| Flag | Format | Notes |
|---|---|---|
| (default in pipes/agents) | TOON | token-efficient, ~40% fewer tokens than JSON |
--json / --format json |
JSON | JSON.parse()-safe |
--format yaml |
YAML | human-readable |
--format md |
Markdown | tables — paste into PRs / issues / docs |
--format jsonl |
JSON Lines | one record per line, streamable |
Other useful global flags: --filter-output <keys> (prune to dot-paths), --token-count / --token-limit n / --token-offset n (manage large outputs), --full-output (full envelope with meta.command / meta.duration).
When stdout is a TTY (humans), output goes pretty-printed. When piped/agent-consumed, you get the structured envelope automatically.
Errors emit { code, message, retryable, hint? } on stderr. Exit codes are stable:
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | user error (bad args, missing wallet, wrong passphrase, account quota) |
| 2 | network error (merchant unreachable, RPC failure) |
| 3 | insufficient funds |
| 4 | payment rejected (exceeds --max-spend, local limit hit) |
| 5 | multi-rail ambiguity (requires --chain or preferred_chains config) |
# Scripted, non-interactive
export AGENTSCORE_PAY_PASSPHRASE=<passphrase>
# Probe without paying
agentscore-pay check https://merchant.example/api --json
# Dry-run a payment (print the plan, don't sign)
agentscore-pay pay POST https://merchant.example/api \
-d '{"x":1}' --max-spend 5 --dry-run --json
# Real pay
agentscore-pay pay POST https://merchant.example/api \
-d '{"x":1}' --max-spend 5 --jsonEvery command — wallet, payment, identity — is exposed as an MCP tool:
agentscore-pay --mcp # start as a stdio JSON-RPC MCP server
agentscore-pay mcp add # register with Claude Code / Cursor / Amp
agentscore-pay --llms # markdown manifest of every command
agentscore-pay --llms --format json # JSON Schema manifest
agentscore-pay <cmd> --schema # JSON Schema for one command's args/options/outputagentscore-pay skills add and agentscore-pay completions register skill files and shell completions.
Every pay invocation generates a stable X-Idempotency-Key header — a SHA-256 hash of (url + method + body + signer) — so retries within a single invocation reuse the same key. Merchants that honor Stripe-pattern dedup won't double-charge if a payment settles but the network response is lost mid-flight. Pass your own -H 'X-Idempotency-Key: <value>' to override (useful for cross-process idempotency: same logical purchase across multiple pay invocations).
AgentScore reserves seven EVM addresses (0x0000…0001 through 0x0000…0007) as deterministic test fixtures — KYC verified, sanctions clear, age gates passing — so dev/test merchants don't burn real KYC credits. Pay exports isAgentScoreTestAddress(addr) from @agent-score/pay/test-mode and AGENTSCORE_TEST_ADDRESSES for completion / fixtures.
Spec-compliant 402 responses carry decimals in the rail requirements. When a merchant omits it, pay applies a strict policy to avoid silent mis-billing:
- Asset is canonical USDC (matched against the per-chain Circle USDC registry pinned in pay) — silently use 6 decimals.
- Asset is anything else — abort with
merchant_spec_violation. Guessing decimals risks orders-of-magnitude mis-billing on tokens with non-6-decimal precision, so pay refuses to pay rather than continuing on partial info.
A typical autonomous agent flow: probe the endpoint, decide whether to pay, pay, branch on the structured outcome.
Bash (Claude Code / Cursor / shell-tool):
#!/usr/bin/env bash
set -eu
URL="https://agents.martinestate.com/purchase"
BODY='{"product_id":"cab-2021","quantity":1,"email":"agent@example.com","shipping":{...}}'
MAX_SPEND=250
# 1. Probe — what does this endpoint cost and which rails does it accept?
PROBE=$(agentscore-pay check "$URL" -X POST -d "$BODY" --json)
PRICE=$(printf '%s' "$PROBE" | jq -r '.accepts[0].max_amount_usd // empty')
echo "Endpoint asks for \$${PRICE} USDC"
# 2. Pay — capture stdout (success body) and exit code separately.
RESPONSE=$(agentscore-pay pay POST "$URL" \
-H 'Content-Type: application/json' \
-d "$BODY" \
--max-spend "$MAX_SPEND" \
--timeout 120 \
--retries 2 \
--json) || EXIT=$?
EXIT=${EXIT:-0}
# 3. Branch on the standard exit codes.
case "$EXIT" in
0) echo "Paid. tx=$(printf '%s' "$RESPONSE" | jq -r '.tx_hash // .body.tx_hash // "?"')" ;;
2) echo "Network/RPC error — retry later." >&2; exit 2 ;;
3) echo "Insufficient funds — top up:"; agentscore-pay fund-estimate "$URL" -X POST -d "$BODY"; exit 3 ;;
4) echo "Rejected (price exceeded --max-spend or local limit)." >&2; exit 4 ;;
5) echo "Multi-rail ambiguity — set --chain or config preferred_chains." >&2; exit 5 ;;
*) echo "User error: $RESPONSE" >&2; exit 1 ;;
esacPython:
import json, subprocess, sys
def pay(url: str, body: dict, max_spend_usd: float) -> dict:
proc = subprocess.run(
["agentscore-pay", "pay", "POST", url,
"-H", "Content-Type: application/json",
"-d", json.dumps(body),
"--max-spend", str(max_spend_usd),
"--timeout", "120", "--retries", "2", "--json"],
capture_output=True, text=True,
)
if proc.returncode == 0:
return json.loads(proc.stdout)
err = json.loads(proc.stderr.splitlines()[-1])
raise RuntimeError(f"pay failed (exit {proc.returncode}): {err['error']['code']} — {err['error']['message']}")
result = pay("https://agents.martinestate.com/purchase",
{"product_id": "cab-2021", "quantity": 1, "email": "a@b.co", "shipping": {}}, 250)
print(result["tx_hash"], result["body"])TypeScript / Node:
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const exec = promisify(execFile);
async function pay(url: string, body: unknown, maxSpendUsd: number) {
try {
const { stdout } = await exec('agentscore-pay', [
'pay', 'POST', url,
'-H', 'Content-Type: application/json',
'-d', JSON.stringify(body),
'--max-spend', String(maxSpendUsd),
'--timeout', '120', '--retries', '2', '--json',
]);
return JSON.parse(stdout);
} catch (err: any) {
const last = (err.stderr ?? '').split('\n').filter(Boolean).pop();
throw new Error(`pay exit ${err.code}: ${last}`);
}
}The CLI never touches stdout for human chrome when --json is passed — every byte on stdout is parseable JSON, every error on stderr is one JSON object per line.
| Chain | Protocol | Library | Network |
|---|---|---|---|
base |
x402 (EIP-3009) | @x402/fetch + @x402/evm |
eip155:8453 |
solana |
MPP solana/charge |
mppx/client + @solana/mpp/client |
solana:5eykt... |
tempo |
MPP tempo/charge |
mppx/client |
chain 4217 |
Solana payments route through MPP solana/charge (Solana Foundation's @solana/mpp package) rather than x402. Tempo is always MPP via mppx/client. Base is the only x402 rail pay funds directly.
The CLI ships with no default rail preference. Algorithm:
--chain Xwas passed → use X (error if not present or insufficient).- Exactly one wallet on disk is funded for the target → use it.
- Multiple funded wallets → check
~/.agentscore/config.jsonpreferred_chainsas a tiebreaker. - Still multiple → error with
code: "multi_rail_candidates"and list the options. - Zero candidates → error with
code: "no_funded_rail"and point tofund.
Config example (~/.agentscore/config.json):
{
"preferred_chains": ["tempo", "base"]
}Or via the CLI:
agentscore-pay config set preferred_chains tempo,base
agentscore-pay config get
agentscore-pay config unset preferred_chainsVerbose mode (-v) logs rail selection + balances to stderr.
| Command | Purpose |
|---|---|
init [--no-mnemonic] [--fund-tempo-testnet] [--preferred-chains <list>] |
One-shot first-run: create all 3 wallets (mnemonic by default) + optional testnet fund + preferred-chain config |
wallet create [--chain c] [--name name] [--mnemonic] |
Generate keystore(s). Omit --chain to create all three. Pass --mnemonic to derive from a BIP-39 seed. --name for named secondary wallets. |
wallet import [<key>] --chain c [--name name] / wallet import --mnemonic "<phrase>" |
Import raw private key (hex/base64) OR a 12/24-word phrase |
wallet list [--chain c] |
List named keystores per chain |
wallet address --chain c [--name name] |
Print the address |
wallet export --chain c [--name name] --danger [--skip-confirm] |
Decrypt + print the private key |
wallet remove --chain c [--name name] --danger [--skip-confirm] |
Irrecoverably delete a keystore |
wallet show-mnemonic --danger [--skip-confirm] |
Decrypt + print the stored BIP-39 mnemonic |
balance [--chain c] [--network n] |
USDC balance across chains (mainnet default; --network testnet for Base Sepolia / Solana Devnet / Tempo testnet) |
qr --chain c [--amount N] [--network n] |
ASCII QR or EIP-681 / solana: URI |
fund --chain c [--amount N] [--network n] |
Receive QR + balance poll. Default amount is 10 USD (~50-200 typical agent calls). Send USDC from any wallet, exchange, or fiat onramp; fund polls until it lands. |
faucet --chain c |
Print testnet faucet URL(s) for the chain + copy your address to clipboard |
fund-estimate <url> [-X method] [-d body] [-H header]... |
Probe a 402-gated URL and report how many calls your balance covers + top-up suggestion |
check <url> [-X method] [-d body] [-H header]... |
Probe 402 response; show accepted rails without paying |
pay <method> <url> [-d body] [-H header]... [--chain c] [--network n] [--max-spend N] [--timeout N] [--retries N] [--dry-run] [-v] |
HTTP request + auto 402 handling. --timeout defaults to 60s and applies to the merchant request only — facilitator settlement may exceed it. --retries only retries pre-flight connection errors (per-scheme nonces prevent double-spend). |
whoami [--network n] |
Wallet + balance summary + active config |
history [--limit N] |
Past payments from ~/.agentscore/history.jsonl |
limits show | set | clear |
Persistent per-call / daily / per-merchant USD spending limits |
config get [key] | set <k> <v> | unset <k> | path |
Read/write ~/.agentscore/config.json (e.g. config set preferred_chains tempo,base) |
discover [--search q] [--chain c] [--max-price N] [--limit N] [--protocol x402|mpp|both] |
List paid services from the x402 Bazaar (Coinbase) and MPP services directory (Tempo). Both queried in parallel by default. |
unlock [--for 15m] | --clear |
Cache passphrase to ~/.agentscore/.unlock (mode 0600) for a bounded TTL — skip per-call prompts during a session |
revoke --chain c --token <addr> --spender <addr> [--network n] |
Send approve(spender, 0) on EVM (base/tempo). Requires native gas. |
passport login/status/logout use the public POST /v1/sessions/public endpoint and require no API key. The other identity commands below (reputation, assess, sessions, credentials, associate-wallet) wrap the AgentScore SDK — set AGENTSCORE_API_KEY.
AgentScore Passport is free for buyers, forever. AgentScore monetizes sellers/merchants — buyers and agents-as-buyers never pay us.
| Command | Purpose |
|---|---|
passport login |
Verify your identity in browser; saves operator_token to ~/.agentscore/passport.json. After login, every pay <url> call auto-attaches X-Operator-Token (suppress with --no-passport). No API key required. |
passport status |
Show stored Passport — token prefix, expiry, expired flag |
passport logout |
Remove the local file (and revoke remotely if AGENTSCORE_API_KEY is set; otherwise local-only) |
reputation <address> [--chain c] |
Cached trust reputation lookup (no API key required) |
assess [--address a | --operator-token o] [--require-kyc] [--min-age N] [--require-sanctions-clear] [--blocked-jurisdictions cc...] [--allowed-jurisdictions cc...] [--refresh] |
On-the-fly assessment with policy (requires API key) |
sessions create [--address a] [--operator-token o] [--context s] [--product-name s] |
Create a verification session — returns verify_url + poll_secret (low-level; passport login is the wrapper most agents want) |
sessions get <id> [--poll-secret s] |
Poll a session — returns operator_token once status is verified |
credentials create [--label s] [--ttl-days N] |
Mint an operator credential (opc_...) |
credentials list |
List active (non-expired) credentials |
credentials revoke <id> |
Revoke a credential by ID |
associate-wallet --operator-token o --wallet-address a --network evm|solana [--idempotency-key k] |
Report a signer wallet seen paying under a credential (cross-merchant attribution) |
assess, sessions, credentials, and associate-wallet surface the SDK's typed errors as structured CliErrors. The JSON envelope's code discriminates the recovery path:
code |
Source | Recovery |
|---|---|---|
config_error |
API-key missing/invalid, OR TokenExpiredError (extra carries verify_url/session_id/poll_secret), OR InvalidCredentialError |
Run passport login to mint a fresh operator_token (no API key needed); for API-key issues, fix AGENTSCORE_API_KEY |
insufficient_balance |
PaymentRequiredError — endpoint not enabled for this account |
Surface next_steps.suggestion to the user; agent retry won't help |
quota_exceeded |
QuotaExceededError — account-level cap hit |
Do NOT retry; surface to the user with https://agentscore.sh/pricing. Use assess response's quota field to monitor approach-to-cap proactively |
network_error |
RateLimitedError (per-second cap), TimeoutError, or any other transient failure |
Retry with backoff per next_steps.suggestion |
assess (and the other identity commands when the account has a per-period quota) emits the response's X-Quota-Limit / X-Quota-Used / X-Quota-Reset headers as a quota: { limit, used, reset } block on the success envelope. Agents monitoring approach-to-cap should warn at 80% and alert at 95%.
agentscore-pay assess --address 0xabc... --json | jq '.quota'
# → { "limit": 1000, "used": 780, "reset": "2026-06-01T00:00:00Z" }quota is absent on accounts with no per-period quota.
# Generate a BIP-39 seed and derive all three chains at once
agentscore-pay wallet create --mnemonic
# Later, on another machine: import the phrase
agentscore-pay wallet import --mnemonic "legal winner thank year wave sausage worth useful legal winner thank yellow"
# Retrieve the stored phrase (prompted for passphrase + type-to-confirm)
agentscore-pay wallet show-mnemonic --dangerDerivation paths: EVM uses m/44'/60'/0'/0/0 (standard), Solana uses m/44'/501'/0'/0' (SLIP-10 Ed25519). The same phrase regenerates identical keys on every machine.
EVM and Solana use different curves: EVM uses secp256k1 (BIP-32 hardened+non-hardened paths), Solana uses Ed25519 (which only supports hardened derivation). The standards differ accordingly:
- EVM (BIP-44, secp256k1) —
m/44'/60'/0'/0/0. The trailing/0/0is non-hardened. MetaMask, Rabby, and Coinbase Wallet all use this path; importing a phrase into any of them yields the same address you see inwallet address --chain base. - Solana (SLIP-10, Ed25519) —
m/44'/501'/0'/0'. All four levels are hardened (note the trailing'). Phantom and Solflare use this path for "Account 0"; importing the same phrase yields the address you see inwallet address --chain solana.
If you import the phrase into Phantom and see a different address, check that Phantom is set to "Standard derivation path" (not the legacy m/44'/501'/0').
Two layers of multi-wallet support:
Each chain can hold multiple keystores. The default name is default; pass --name <name> to address others:
agentscore-pay wallet create --chain base --name trading
agentscore-pay wallet list # enumerate per chain
agentscore-pay balance --chain base --name trading
agentscore-pay pay POST <url> --chain base --name trading -d '...' --max-spend 5Names are limited to [a-z0-9-] (max 32 chars). Mnemonic-derived wallets are always stored under default — for additional named wallets use random keys (wallet create) or import (wallet import).
# Default wallet for general spending
agentscore-pay init # creates base/solana/tempo "default"
agentscore-pay fund --chain base --amount 10 # tops up default
# Separate "trading" wallet for a high-budget bot
agentscore-pay wallet create --chain base --name trading
agentscore-pay wallet address --chain base --name trading
# → 0xTRADINGADDRESS — fund this address externally (CEX withdrawal, transfer, etc.)
agentscore-pay balance --chain base --name trading
# Inspect everything
agentscore-pay wallet list
# base default
# base trading
# Pay from each
agentscore-pay pay POST https://merchant.example/api -d '{}' --chain base # uses default
agentscore-pay pay POST https://merchant.example/api -d '{}' --chain base --name trading # uses trading
# Remove a wallet (irrecoverable — back up the mnemonic or export the key first)
agentscore-pay wallet export --chain base --name trading --danger --skip-confirm > trading.key
agentscore-pay wallet remove --chain base --name trading --danger --skip-confirmPer-wallet limits aren't supported today (limits are global). Use separate AGENTSCORE_PAY_HOME profiles if you need per-wallet daily caps.
Set AGENTSCORE_PAY_HOME to isolate completely (different history.jsonl, limits.json, config.json):
# One profile for production merchants
AGENTSCORE_PAY_HOME=~/.agentscore-prod agentscore-pay wallet create
# Another profile for testnet development
AGENTSCORE_PAY_HOME=~/.agentscore-test agentscore-pay wallet create
AGENTSCORE_PAY_HOME=~/.agentscore-test agentscore-pay pay --network testnet ...Three ways to satisfy the passphrase prompt, in precedence order:
| Mechanism | Best for | Persistence |
|---|---|---|
AGENTSCORE_PAY_PASSPHRASE=<pass> env var |
Containers, CI, serverless, daemons, any non-interactive agent | Lifetime of the process / shell session |
agentscore-pay unlock --for 1h |
Interactive shell session where you'll run multiple commands | Cached in ~/.agentscore/.unlock (mode 0600) until TTL expires (max 8h); unlock --clear wipes early |
| Per-call interactive prompt | First-time setup, one-off commands | None — never written |
Env var wins when set: it produces no on-disk artifact and is the right primitive for every agent context (CI secrets, container env, K8s secrets, Lambda config, MCP host config). When env vars aren't controllable (e.g. an interactive Claude Code session running locally), unlock is the fallback.
For agent authors: prefer env var. Read it from your secret store at agent startup; don't bake it into the agent's prompt or memory. Pay's agent-guide command (agentscore-pay agent-guide) explains the precedence in its own structured output.
The wallet holds USDC only — no ETH or SOL required. x402 (EIP-3009) and MPP Tempo are both gasless for the signer; the facilitator pays.
- All chains —
agentscore-pay fund --chain <chain> --amount 10prints an ASCII QR and your wallet address, then polls balance until the deposit lands. Send USDC from any source: another wallet (MetaMask, Rabby, Coinbase Wallet, Phantom), a CEX withdrawal, or any third-party fiat onramp that supports the destination chain (Coinbase Pay, MoonPay, Transak, Onramper, Stripe Crypto Onramp, etc.). Default amount is$10(~50-200 typical agent calls). - Tempo specifics — most fiat-onramp partners don't cover Tempo (chain 4217) yet. Fund by transferring USDC.e from another Tempo wallet, or via a bridge (LayerZero / Squid / Relay) from Base.
- No-frills receive —
agentscore-pay wallet address --chain baseprints just the address if you already know your funding source.
| Chain | UX | Time-to-funded |
|---|---|---|
| Base Sepolia | faucet --chain base — prints Circle URL + copies your address to clipboard. Paste into the form and wait. |
~30s + manual paste |
| Solana Devnet | faucet --chain solana — same Circle flow. |
~30s + manual paste |
| Tempo testnet | fund --chain tempo --network testnet is the only programmatic faucet — calls Moderato's tempo_fundAddress JSON-RPC, mints 4 test stablecoins (pathUSD, AlphaUSD, BetaUSD, ThetaUSD) directly. No browser, no captcha. |
~5s, fully scripted |
Use fund --chain tempo --network testnet in CI/agent setup scripts — it's the only one that works without human interaction. Base Sepolia and Solana Devnet still require pasting your address into Circle's web form.
- Pre-fund a wallet on your laptop, then
wallet export --chain base --danger --skip-confirmto get the key. - On the server,
AGENTSCORE_PAY_PASSPHRASE=<pass> agentscore-pay wallet import --chain base 0x<hex>or ship the encrypted~/.agentscore/wallets/base.jsondirectly. AGENTSCORE_PAY_HOME=/opt/agentscorein the server env isolates state from any other user on the machine.agentscore-pay limits set --daily 50 --per-call 1caps spending for autonomous agents.
# Before making a purchase, check what you can afford
agentscore-pay fund-estimate https://agents.martinestate.com/purchase \
-X POST -d '{"product_id":"cab-2021","quantity":1,...}'
# → shows price, your balance, calls affordable, and suggested top-up- Keystore is AES-256-GCM encrypted with a scrypt-derived key, one file per chain.
- Files written with
0600perms, parent dir0700. - Passphrase prompted per signing operation; override with
AGENTSCORE_PAY_PASSPHRASEenv var for non-interactive agents. wallet exportis guarded by--danger+ "type EXPORT" prompt.- Local spending limits (
limits set --daily N --per-call N --per-merchant N) enforce at signing time via the x402 and MPP hooks. ~/.agentscore/history.jsonlrecords successful payments (url, host, chain, protocol, status, timestamp). No secrets logged.- No telemetry. No auto-update. No plaintext keys on disk.
For interactive humans: any 8+ char passphrase you'll remember is fine — the scrypt-256-GCM combination is robust against offline brute force at typical human-passphrase entropy levels.
For autonomous agents: the passphrase usually lives in AGENTSCORE_PAY_PASSPHRASE (env var) or ~/.agentscore/.unlock (file). Both are filesystem/process-readable to anyone with shell access as that user, so the passphrase isn't really a separate trust boundary — it's primarily protecting the keystore against theft of the on-disk file alone. A long, random passphrase makes the file useless if exfiltrated:
# generate a 32-byte (256-bit) random passphrase
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# 4d2a...
# stash it where your agent can read it (env / secret manager / .env / etc.)
export AGENTSCORE_PAY_PASSPHRASE=4d2a...If the wallet keystore and the passphrase store are both compromised, the wallet is compromised — there's no extra protection from a complex passphrase. Defend the directory.
Native binaries attached to each GitHub Release are signed with sigstore/cosign keyless OIDC. To verify a downloaded binary:
cosign verify-blob \
--signature agentscore-pay-darwin-arm64.sig \
--certificate agentscore-pay-darwin-arm64.pem \
--certificate-identity-regexp 'https://github.com/agentscore/.+' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
agentscore-pay-darwin-arm64A successful verification (Verified OK) confirms the binary was built by a workflow in the agentscore GitHub org against the published source — not tampered post-build. The .sig and .pem files are uploaded next to each binary in the release.
The npm package itself is published with npm provenance (also sigstore-backed) — npm install @agent-score/pay inherits the same trust chain automatically.
| Variable | Purpose |
|---|---|
AGENTSCORE_PAY_PASSPHRASE |
skip interactive passphrase prompt |
AGENTSCORE_PAY_HOME |
override state dir (default ~/.agentscore) — lets you run multiple wallet profiles |
BASE_RPC_URL |
override Base mainnet RPC endpoint |
BASE_SEPOLIA_RPC_URL |
override Base Sepolia RPC endpoint |
SOLANA_RPC_URL |
override Solana mainnet RPC endpoint |
SOLANA_DEVNET_RPC_URL |
override Solana Devnet RPC endpoint |
TEMPO_RPC_URL |
override Tempo mainnet RPC endpoint |
TEMPO_TESTNET_RPC_URL |
override Tempo testnet RPC endpoint |
AGENTSCORE_API_KEY |
API key for identity commands (assess, sessions, credentials, associate-wallet, reputation) |
@agent-score/pay is the universal agent-payment CLI; it works with any 402/MPP merchant regardless of whether they use AgentScore for identity. The packages below are AgentScore's optional identity + integration layer for merchants who choose to use it:
@agent-score/sdk— TypeScript client for the AgentScore API@agent-score/commerce— merchant-side SDK: trust-gating middleware (/identity/{hono,express,fastify,nextjs,web}) plus 402 / payment / discovery / Stripe-multichain helpers@agent-score/pay(this package) — agent-side CLI: wallet + payment across x402/MPP rails + identity commands (assess, sessions, credentials, associate-wallet, reputation). Doubles as an MCP server via--mcp.
When a merchant uses @agent-score/commerce, wallet-to-operator linking happens merchant-side via captureWallet — pay does not duplicate the POST /v1/credentials/wallets call. For non-AgentScore merchants this is a no-op; pay does not contact AgentScore APIs unless the merchant's 402 challenge requires AgentScore identity.
MIT