Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg)](https://www.typescriptlang.org/)
[![Base · x402](https://img.shields.io/badge/Base-x402-fc6f6f.svg)](https://x402.org)

Open-source toolkit for **h402 — the x402 router for agent capabilities**. One endpoint per task: providers compete behind each capability, h402 auto-pins the best one per call, and settles in Base USDC over x402.
Open-source toolkit for **h402 — the x402 capability store for agents**. Discover a task, inspect its enabled providers and provider-native contracts, then execute one concrete provider path with Base USDC settlement when required.

> x402 is the rail. h402 is the router.
> x402 is the payment rail. h402 is the capability store and execution surface.

- **Browse capabilities** → https://h402.hunt.town/catalog
- **Docs & agent quickstart** → https://h402.hunt.town/docs
Expand All @@ -26,15 +26,17 @@ Open-source toolkit for **h402 — the x402 router for agent capabilities**. One
```bash
npm install -g @h402/cli

h402 search "web search"
h402 quote web/search --json '{"query":"agent payments"}'
h402 call ai/news # free; no wallet required
h402 search "web search" # compact route/provider summaries
h402 show web/search # full route + all provider contracts
h402 show web/search --provider stableenrich-exa # one full provider-native contract
h402 quote web/search --provider stableenrich-exa --json '{"query":"agent payments"}'
h402 call ai/news # free; omitted provider resolves defaultProvider

# Set up a signer only when you want to call a route that returns a payable 402:
h402 wallet list # read-only native-binding preflight; [] is OK
h402 wallet create --name agent
h402 wallet fund --name agent
h402 call web/search --name agent --json '{"query":"agent payments"}'
h402 call web/search --provider stableenrich-exa --name agent --json '{"query":"agent payments"}'
```

Browsing, quoting, and free-route calls do not require a local wallet. Wallet creation creates a local signing wallet only; `h402 auth` creates the optional bonus-credit session. A funded local wallet is required only if the first response is a payable `402`.
Expand All @@ -47,11 +49,13 @@ OWS wallet creation and signing use native bindings available only on macOS and

## How it works

You call a task (`category/action`) before the CLI resolves a wallet. An initial 2xx is returned directly — `h402.paidBy` says whether it was `free` (no charge) or covered by bonus `credit` from an authenticated session. Only when the first response is an x402 `402 PAYMENT-REQUIRED` does the CLI resolve a funded local wallet, sign a Base USDC EIP-3009 authorization locally, and retry. Pass `--max-usd <amount>` (or store a string `maxUsd`, such as `"0.05"`, in `~/.h402/config.json`) to refuse signing a challenge above that USDC cap. Keys never leave your machine.
Each call uses one concrete provider. Without `--provider`, the CLI resolves the route's current `defaultProvider` from full catalog detail before sending the call. Successes include `h402.cliProviderSelection`, and post-resolution failures include the same metadata at `error.detail.h402.cliProviderSelection`. Its `pinnedCommand` is a shell-escaped fresh-call recipe that preserves non-secret request, backend, wallet, and payment-safety flags and omits passphrases and the previous idempotency key. Passing `--provider` skips default resolution and calls that pinned path directly. A `410` response is never retried automatically: read `error.detail.error.candidates`, inspect the replacement with `h402 show`, then start a new explicit call. An unknown route preserves `error.detail.error.recovery.command`, which points back to `h402 search`.

A successful `call` prints `{ "data": <provider result>, "meta"?: <contract metadata>, "h402": <routing metadata> }`: the upstream provider's JSON is under `data`; route-level normalized metadata may appear under `meta`; and `h402` always carries `routeId`, `provider`, `selectedCandidateId`, `routing`, and `paidBy`. `ledgerEntryId` is present for credit or x402-paid calls; `paymentTransaction` and CLI-added `signedAmount` are x402-payment-only fields; free calls omit all three. Optional `followUp` instructions describe async work. Do not discard `meta` — it is part of the route contract when present. On failure the CLI exits non-zero and writes `{ "error": { "message", "detail"? } }` to stderr — `message` is a human-readable diagnostic, and `detail` carries the backend's JSON error when the request reached the backend.
After provider resolution, the CLI sends the request before resolving a wallet. An initial 2xx is returned directly — `h402.paidBy` says whether it was `free` (no charge) or covered by bonus `credit` from an authenticated session. Only when the first response is an x402 `402 PAYMENT-REQUIRED` does the CLI resolve a funded local wallet, sign a Base USDC EIP-3009 authorization locally, and retry the same pinned provider path. Pass `--max-usd <amount>` (or store a string `maxUsd`, such as `"0.05"`, in `~/.h402/config.json`) to refuse signing a challenge above that USDC cap. Keys never leave your machine.

Async routes may return a job receipt instead of the final result. Async parent route IDs end in `-async`; a single-parent follow-up is `<parent-route>-status`, while shared multi-parent follow-ups may use a shared `*-status` name. When `h402.followUp` is present, follow its `method`, `path`, `params.jobId`, `docsUrl`, and `instruction` (or the route's `*-status` capability) until the job completes. The follow-up path is provider-bound, so preserve the provider segment from that path when translating the instruction to CLI form. Match `followUp.method` — GET params go via `--query`, POST bodies via `--json`; the CLI rejects `--query` on a POST (`<followUp.params>` means its JSON-encoded object):
A successful `call` prints `{ "data": <provider-native body>, "meta"?: <reserved envelope metadata>, "h402": <execution metadata> }`: `data` stays provider-native, optional `meta` remains reserved envelope metadata rather than normalized provider output, and `h402` carries the provider-pinned execution receipt plus CLI-added `cliProviderSelection`. `ledgerEntryId` is present for credit or x402-paid calls; `paymentTransaction` and CLI-added `signedAmount` are x402-payment-only fields; free calls omit all three. Optional `h402.followUp` instructions describe async work. On failure the CLI exits non-zero and writes `{ "error": { "message", "detail"? } }` to stderr — `message` is human-readable and `detail` preserves the backend recovery body unchanged.

Async routes may return a job receipt instead of the final result. Async parent route IDs end in `-async`; a single-parent follow-up is `<parent-route>-status`, while shared multi-parent follow-ups may use a shared `*-status` name. When `h402.followUp` is present, follow its provider-native `params` object together with `method`, `path`, `docsUrl`, and `instruction` until the provider reports completion. The follow-up path is provider-bound, so preserve its provider segment. Match `followUp.method` — GET params go via `--query`, POST bodies via `--json`; the CLI rejects `--query` on a POST (`<followUp.params>` means its JSON-encoded object):

```bash
# followUp.method GET (most status polls):
Expand All @@ -65,7 +69,7 @@ h402 call <followUp.routeId> \
--json '<followUp.params>'
```

Auto routing capability-routes provider-native input to an enabled candidate whose strict schema accepts it. `web/search` accepts common fields such as `query` and `limit` on the default `auto` route, and capable candidates can also accept native fields such as `freshness` without a pin. Use `--provider` only for determinism, deliberate provider selection, or provider-bound follow-ups.
`h402 search` returns compact route/provider summaries. Use `h402 show <route>` for full provider-native schemas and samples, then pin a provider for reproducibility.

## Development

Expand Down
48 changes: 27 additions & 21 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
name: h402
description: >-
Call any agent capability — web search, crypto & market data, maps, social,
finance, security checks, OCR, weather, and more — through one endpoint and
pay per call in Base USDC over x402, using the open-source h402 CLI. Use when
finance, security checks, OCR, weather, and more — through h402's capability
store and concrete provider paths, paying per call in Base USDC over x402 with
the open-source h402 CLI. Use when
an agent needs live external data or a paid API without managing per-provider
API keys or subscriptions.
---

# h402 — pay-per-call capabilities for AI agents

h402 is the **x402 router for agent capabilities**: one canonical endpoint per task.
You call the *task* (e.g. `web/search`), and h402 routes the call to the best provider
and returns a free result or settles a payable challenge in Base USDC. Behind each
capability, providers compete on price and live quality; h402 auto-pins the best one
to your call. No per-vendor API keys or subscriptions; a funded wallet is needed only
for a payable challenge.
h402 is the **x402 capability store for agents**. Discover a task, inspect its enabled
providers and provider-native contracts, then call one concrete provider path. h402
returns a free result or settles a payable challenge in Base USDC without per-vendor
API keys or subscriptions. A funded wallet is needed only for a payable challenge.

## When to use this

Expand All @@ -37,9 +36,11 @@ npm install -g @h402/cli # install the CLI
Calls go to the production backend (`https://h402.hunt.town`) by default; set `H402_API_URL` or `--api-url` to point at another backend.

```bash
h402 search "AI news"
h402 quote web/search --json '{"query":"agent APIs"}'
h402 call ai/news # direct 2xx; no wallet or payment
h402 search "web search" # compact summaries
h402 show web/search # full route + all provider contracts
h402 show web/search --provider stableenrich-exa # one full provider-native contract
h402 quote web/search --provider stableenrich-exa --json '{"query":"agent APIs"}'
h402 call ai/news # direct 2xx; omitted provider resolves defaultProvider
```

Wallet creation creates a local signing wallet only; `h402 auth` creates the optional bonus-credit session. A funded local wallet is required only if the first response is a payable `402`.
Expand All @@ -63,26 +64,31 @@ h402 wallet balance --name agent

A few dollars of USDC covers hundreds of calls — most routes cost **$0.001–$0.05** each.

## The loop: find → (quote) → call
## The loop: find → inspect → (quote) → call

```bash
# 1. Find a route (returns JSON catalog matches)
# 1. Find a route (compact JSON summaries)
h402 search "token holders"

# 2. (optional) Preview the price before paying
h402 quote crypto/token-holders --json '{"tokenAddress":"0x37f0c2915CeCC7e977183B8543Fc0864d03E064C","chain":"base"}'
# 2. Inspect full provider-native contracts and samples
h402 show crypto/token-holders
h402 show crypto/token-holders --provider nansen

# 3. Call it — pays automatically on the 402 challenge, returns the JSON result
h402 call crypto/token-holders --name agent \
--json '{"tokenAddress":"0x37f0c2915CeCC7e977183B8543Fc0864d03E064C","chain":"base"}'
# 3. (optional) Preview the price for that concrete provider
h402 quote crypto/token-holders --provider nansen \
--json '{"chain":"base","token_address":"0x833589fCD6eDb6E08f4C7C32D4f71b54bdA02913"}'

# 4. Call it — pays on a 402 challenge and keeps the provider pinned
h402 call crypto/token-holders --provider nansen --name agent \
--json '{"chain":"base","token_address":"0x833589fCD6eDb6E08f4C7C32D4f71b54bdA02913"}'
```

- A route id is `category/action` (e.g. `web/search`, `maps/place-details`, `finance/stock-quote`).
- `--json '{...}'` is the request body; use `--query '{...}'` for GET query params instead.
- Auto routing capability-routes provider-native input to an enabled candidate whose strict schema accepts it. `web/search` accepts common fields such as `query` and `limit` on the default `auto` route, and capable candidates can also accept native fields such as `freshness` without a pin. Use `--provider` only for determinism, deliberate provider selection, or provider-bound follow-ups.
- Each call uses one concrete provider. Without `--provider`, the CLI resolves the route's current `defaultProvider` from full catalog detail before execution. Successes record the choice in `h402.cliProviderSelection`; post-resolution failures record it at `error.detail.h402.cliProviderSelection`. The shell-escaped `pinnedCommand` is a fresh-call recipe that keeps non-secret request, backend, wallet, and payment-safety flags but omits passphrases and the previous idempotency key. Prefer explicit `--provider` after inspection for reproducibility. A `410` response is never retried automatically; inspect `error.detail.error.candidates` and start a new explicit call only after choosing one. For an unknown route, follow the preserved `error.detail.error.recovery.command` search guidance.
- Every command prints **JSON to stdout** (including `wallet fund` and `wallet balance`); failures print to stderr and exit non-zero.
- A successful `call` returns `{ "data": <provider result>, "meta"?: <contract metadata>, "h402": <routing metadata> }` — read the provider output from `data`, preserve `meta` when present, and inspect `h402` for `routeId`, `provider`, `selectedCandidateId`, `routing`, and `paidBy`. `ledgerEntryId` is present for credit or x402-paid calls; `paymentTransaction` and CLI-added `signedAmount` are x402-payment-only fields; free calls omit all three. Optional `followUp` describes async work. A failure exits non-zero and writes `{ "error": { "message", "detail"? } }` to stderr — read `error.message` for the reason, `error.detail` for the backend's JSON error when present.
- Async parent route IDs end in `-async`; a single-parent follow-up is `<parent-route>-status`, while shared multi-parent follow-ups may use a shared `*-status` name. If `h402.followUp` is present, the response is a job receipt, not the final result. Follow `h402.followUp.method`, `path`, `params.jobId`, `docsUrl`, and `instruction` (or the route's `*-status` capability) until the async job completes. The follow-up path is provider-bound, so preserve its provider segment in the CLI call. Match `followUp.method` — GET params go via `--query`, POST bodies via `--json`; the CLI rejects `--query` on a POST (`<followUp.params>` means its JSON-encoded object):
- A successful `call` returns `{ "data": <provider-native body>, "meta"?: <reserved envelope metadata>, "h402": <execution metadata> }` — `data` remains provider-native, optional `meta` is reserved envelope metadata rather than normalized provider output, and `h402` carries the execution receipt plus `cliProviderSelection`. `ledgerEntryId` is present for credit or x402-paid calls; `paymentTransaction` and CLI-added `signedAmount` are x402-payment-only fields; free calls omit all three. Optional `h402.followUp` describes async work. A failure exits non-zero and writes `{ "error": { "message", "detail"? } }` to stderr; `detail` preserves the backend recovery body unchanged.
- Async parent route IDs end in `-async`; a single-parent follow-up is `<parent-route>-status`, while shared multi-parent follow-ups may use a shared `*-status` name. If `h402.followUp` is present, the response is a job receipt, not the final result. Pass its provider-native `params` object according to `method` and preserve the provider from `path`. Match `followUp.method` — GET params go via `--query`, POST bodies via `--json`; the CLI rejects `--query` on a POST (`<followUp.params>` means its JSON-encoded object):

```bash
# followUp.method GET (most status polls):
Expand Down
Loading
Loading