Commands
Every subcommand returns a structured envelope under --json. For the
walkthrough, see Quickstart.
Global flags
Section titled “Global flags”| Flag | Default | Description |
|---|---|---|
--json | off | structured envelope to stdout |
--quiet | off | body to stdout only (no envelope chrome) |
--project <name> | resolved | overrides project resolution |
--gateway <url> | https://api.pactnetwork.io | gateway URL |
--rpc <url> | https://api.mainnet-beta.solana.com | Solana RPC |
--cluster <c> | mainnet | cluster (mainnet only in v1) |
The envelope contract
Section titled “The envelope contract”Every --json invocation returns:
{ "status": "ok", "body": { /* command-specific */ }, "meta": { /* optional, present on covered calls */ }}status values: see Status taxonomy. body shape
is per-command. meta is present on covered calls and carries slug,
call_id, latency_ms, outcome, premium_lamports, premium_usdc,
tx_signature, settlement_eta_sec when the gateway returns them.
pact <url> — make a covered call
Section titled “pact <url> — make a covered call”Default when the first positional arg is a URL. Looks up the slug in the discovery cache, takes a premium, proxies through the gateway.
pact --json https://api.helius.xyz/v0/addresses/<addr>/balances| Flag | Default | Description |
|---|---|---|
--method <m> | GET | HTTP method |
--header <h> | — | repeatable HTTP header |
-d, --data <body> | — | request body |
--raw | off | skip slug rewriting (no coverage) |
--timeout <sec> | 30 | timeout in seconds |
Success envelope:
{ "status": "ok", "body": { /* upstream response */ }, "meta": { "slug": "helius-rpc", "call_id": "...", "latency_ms": 312, "outcome": "ok", "premium_usdc": 0.0001, "tx_signature": null, "settlement_eta_sec": 600 }}Common failures: no_provider (hostname unknown), endpoint_paused,
needs_funding, discovery_unreachable.
pact pay <tool> [args...] — refund-backed 402 wrapper
Section titled “pact pay <tool> [args...] — refund-backed 402 wrapper”Drop-in for solana-foundation/pay
(pay.sh): same argv, exit codes, and x402 + MPP wire format, plus
Pact’s chargeback layer. On a 402, pact pay parses the challenge,
signs a pact-allowance authorization, and re-runs the wrapped tool
with the retry header attached.
pact pay curl https://api.example.com/v1/quote/AAPLpact pay curl -X POST -d '{...}' https://api.example.com/v1/ordersWraps curl only as of v0.3.0.
pact pay and pact approve sign with pay.sh’s active account
(resolution: PACT_PRIVATE_KEY → pay’s active account → throw). Same
wallet pays the merchant and holds the allowance — fund pay once. On
every payment attempt, stderr gets:
[pact] wallet: pay/default (4Zx9…k2Vp)On success, the wrapped tool’s stdout/stderr/exit pass through. With
--json: success is x402_payment_made or mpp_payment_made (exit 0)
and .body.tool_exit_code carries the wrapped tool’s exit.
Failures get dedicated non-zero exits so shell chains break on typo or rejected challenge:
| Status | Exit | When |
|---|---|---|
unsupported_tool | 50 | tool isn’t in SUPPORTED_TOOLS (currently only curl) — fires even with the mainnet gate closed so chains stop on typos |
tool_missing | 51 | tool is supported but not installed on $PATH |
payment_failed | 31 | a 402 challenge was parsed but the retry was rejected — see body.scheme and body.reason |
client_error | 0 | unknown 402 envelope, no supported network, MPP session-challenge, or mainnet gate closed |
If no wallet resolves, coverage is skipped with [pact] coverage skipped: no wallet — set up pay or PACT_PRIVATE_KEY; the wrapped
tool’s exit code is unchanged.
pact balance — wallet + allowance state
Section titled “pact balance — wallet + allowance state”Reports ATA balance, allowance granted to SettlementAuthority, and an
eligible flag mirroring what the program sees at debit time.
pact balance --json{ "status": "ok", "body": { "wallet": "<base58>", "ata": "<base58>", "ata_balance_usdc": 12.5, "allowance_usdc": 5, "eligible": true }}When eligible is false, body.reason is one of:
no_allowance, insufficient_balance, insufficient_allowance.
pact approve <usdc> — grant settlement allowance
Section titled “pact approve <usdc> — grant settlement allowance”SPL Token Approve delegating up to <usdc> from your ATA to
SettlementAuthority. Funds stay in your ATA; the protocol debits up
to the allowance at settlement.
Signs with pay.sh’s active account (default) or PACT_PRIVATE_KEY.
Silent no-op if pay’s account has no SOL — fund pay first.
pact approve 5{ "status": "ok", "body": { "tx_signature": "<base58>", "confirmation_pending": false, "allowance_usdc": 5 }}If the amount exceeds the per-deposit cap or session total in
~/.config/pact/<project>/policy.yaml, returns auto_deposit_capped
(exit 11) without sending.
pact revoke — remove the allowance
Section titled “pact revoke — remove the allowance”SPL Token Revoke on the agent’s ATA — SettlementAuthority can’t
debit until you approve again. Signs with the same wallet as approve.
pact revokepact agents show [pubkey] — inspect calls and balances
Section titled “pact agents show [pubkey] — inspect calls and balances”Reads ${gateway}/v1/agents/<pubkey> — recent calls, refunds,
aggregate stats. Defaults to the project wallet’s pubkey.
pact agents show --jsonpact agents show <other-agent-pubkey> --jsonThe body is the gateway response verbatim. See Protocol Reference → Endpoints for the response schema.
pact agents watch [pubkey] — stream live events
Section titled “pact agents watch [pubkey] — stream live events”Streams SSE from ${gateway}/v1/agents/<pubkey>/events as JSON lines.
Runs until killed.
pact agents watch# {"type":"call","slug":"helius-rpc","outcome":"ok","premium_usdc":0.0001,...}# {"type":"settlement","tx_signature":"...","settled_calls":12,...}pact calls show <call_id> — inspect a single covered call
Section titled “pact calls show <call_id> — inspect a single covered call”Reads ${gateway}/v1/calls/<call_id> — outcome, latency, premium,
refund (if any), and the on-chain settlement signature once batched.
<call_id> is the UUIDv4 from the X-Pact-Call-Id response header
(also meta.call_id on pact <url> --json).
pact calls show 11111111-2222-4333-8444-555555555555 --jsonThe ID is validated as RFC 4122 UUIDv4 before any network round-trip. A typo or a pasted wallet pubkey returns immediately:
{ "status": "client_error", "body": { "error": "invalid_call_id", "message": "Call IDs are UUIDv4 (e.g. 11111111-2222-4333-8444-555555555555). Pass a wallet pubkey to `pact agents show` instead.", "call_id": "<what-you-passed>" }}pact init — install the agent skill
Section titled “pact init — install the agent skill”Writes .claude/skills/pact/SKILL.md and appends a snippet to
CLAUDE.md (or AGENTS.md if present) unless the marker is already
there. Idempotent.
pact init{ "status": "ok", "body": { "skill_installed": "/path/to/.claude/skills/pact/SKILL.md", "claude_md_updated": "/path/to/CLAUDE.md" }}See Quickstart → Agent integration for skill behavior in Claude Code / Codex.
Status taxonomy
Section titled “Status taxonomy”Exit codes map 1:1 from status — useful for shell pipelines that
branch without parsing JSON.
| Status | Exit | Meaning |
|---|---|---|
ok | 0 | call succeeded |
client_error | 0 | bad request — your fault |
server_error | 0 | upstream failed — refund queued |
needs_funding | 10 | ATA balance / allowance insufficient |
auto_deposit_capped | 11 | hit the per-deposit or session-total cap |
endpoint_paused | 12 | provider disabled at gateway |
no_provider | 20 | hostname not in discovery cache (terminal in private beta) |
discovery_unreachable | 21 | gateway unreachable |
signature_rejected | 30 | clock skew — sync NTP |
payment_failed | 31 | pact pay parsed a 402 but the retry was rejected |
x402_payment_made | 0 | pact pay --json succeeded via x402 retry |
mpp_payment_made | 0 | pact pay --json succeeded via MPP retry |
needs_project_name | 40 | project name could not be resolved |
unsupported_tool | 50 | pact pay <tool> where <tool> is not in SUPPORTED_TOOLS |
tool_missing | 51 | pact pay <tool> where <tool> is supported but not on $PATH |
cli_internal_error | 99 | unexpected CLI error |
Environment variables
Section titled “Environment variables”| Var | Effect |
|---|---|
PACT_MAINNET_ENABLED=1 | required closed-beta gate; without it every on-chain command short-circuits to client_error |
PACT_PRIVATE_KEY | bypass the disk wallet (base58 64-byte secret) |
PACT_GATEWAY_URL | override gateway URL |
PACT_RPC_URL | override Solana RPC URL |
PACT_CLUSTER | only mainnet is accepted in v1 |
PACT_PROJECT | override project name resolution |
PACT_AUTO_DEPOSIT_DISABLED=1 | block pact approve entirely |
Configuration files
Section titled “Configuration files”Per-project state under ~/.config/pact/<project>/:
wallet.json— keypair, mode0600. Gateway flow only.policy.yaml— auto-approve caps (per_deposit_max_usdc,session_total_max_usdc); also gatespact approve.endpoints-cache.json— last fetched discovery entries.
pact pay / pact approve read pay.sh’s account from
~/.config/pay/accounts.yml via pay account export <name> -.
What’s next
Section titled “What’s next”- Quickstart — the 60-second walkthrough.
- Troubleshooting — failure modes and fixes.
- Classifier & refund policy — refund math.