@cryptonly/x402 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +61 -87
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -4,60 +4,22 @@
4
4
 
5
5
  # Cryptonly — x402 facilitator
6
6
 
7
- Facilitator client for x402 payments.
7
+ Accept x402 payments in Node.js, with Cryptonly as the facilitator.
8
8
 
9
- [Website](https://cryptonly.net) · [Documentation](https://docs.cryptonly.net/api-reference/openapi/operations/x402supported/) · [Contact](https://cryptonly.net/contact/)
9
+ [Website](https://cryptonly.net) · [Documentation](https://docs.cryptonly.net/guides/x402/) · [Contact](https://cryptonly.net/contact/)
10
10
 
11
11
  </div>
12
12
 
13
13
  ---
14
14
 
15
- Pass it to `x402ResourceServer` from `@x402/express`, `@x402/hono`, or `@x402/next`.
15
+ Cryptonly verifies and settles each payment, and pays the network fee. Payments go straight to your wallet. There are two ways to use this package:
16
16
 
17
- ```bash
18
- npm install @cryptonly/x402
19
- ```
20
-
21
- `@x402/core` ^2 is a peer dependency. Also install the framework package you use, such as `@x402/express` or `@x402/evm`.
22
-
23
- ```ts
24
- import { CryptonlyFacilitatorClient } from '@cryptonly/x402';
25
- import { ExactEvmScheme } from '@x402/evm/exact/server';
26
- import { x402ResourceServer } from '@x402/express';
27
-
28
- const facilitator = new CryptonlyFacilitatorClient({
29
- apiKey: process.env.CRYPTONLY_API_KEY!,
30
- });
31
-
32
- const server = new x402ResourceServer(facilitator).register(
33
- 'eip155:8453',
34
- new ExactEvmScheme(),
35
- );
36
- ```
37
-
38
- ## Options
39
-
40
- | Option | Default | |
41
- | --- | --- | --- |
42
- | `apiKey` | required | Your Cryptonly API key, with the `x402.verify` and `x402.settle` scopes. Sent as `x-tenant-api-key` on every facilitator call. |
43
- | `sandbox` | `false` | Use the sandbox facilitator, which settles on Base Sepolia (`eip155:84532`). |
44
- | `baseUrl` | — | Merchant API origin, for example a local API. `/x402` is appended. Takes precedence over `sandbox`. |
45
-
46
- ```ts
47
- // Sandbox: Base Sepolia, with test USDC from the Circle faucet.
48
- const facilitator = new CryptonlyFacilitatorClient({
49
- apiKey: process.env.CRYPTONLY_API_KEY!,
50
- sandbox: true,
51
- });
52
- const server = new x402ResourceServer(facilitator).register(
53
- 'eip155:84532',
54
- new ExactEvmScheme(),
55
- );
56
- ```
17
+ - **Prices in the dashboard.** `cryptonlyPaymentMiddleware` for Express loads your prices from the Cryptonly dashboard. A price change needs no deploy.
18
+ - **Prices in your code.** `CryptonlyFacilitatorClient` plugs into the stock `@x402/express`, `@x402/hono` or `@x402/next` middleware.
57
19
 
58
- ## Dashboard-configured routes
20
+ You need a Cryptonly API key with the `x402.verify` and `x402.settle` scopes. The [quickstart](https://docs.cryptonly.net/guides/x402/quickstart/) covers getting one.
59
21
 
60
- `@cryptonly/x402/express` reads your paid resources, prices and payout address from the Cryptonly dashboard, so you do not write routes in code. A price change in the dashboard reaches production within a minute, without a deploy.
22
+ ## Prices in the dashboard
61
23
 
62
24
  ```bash
63
25
  npm install @cryptonly/x402 @x402/core @x402/express @x402/evm express
@@ -68,72 +30,84 @@ import express from 'express';
68
30
  import { cryptonlyPaymentMiddleware } from '@cryptonly/x402/express';
69
31
 
70
32
  const app = express();
33
+ app.get('/health', (_req, res) => res.send('ok')); // free routes go first
71
34
 
72
- app.get('/health', (_req, res) => res.send('ok')); // free routes first
73
-
74
- const payments = cryptonlyPaymentMiddleware({
75
- apiKey: process.env.CRYPTONLY_API_KEY!, // scopes x402.verify and x402.settle
76
- });
35
+ const payments = cryptonlyPaymentMiddleware({ apiKey: process.env.CRYPTONLY_API_KEY! });
77
36
  app.use(payments);
78
37
 
79
- // Priced in the dashboard as `GET /weather/:city`.
38
+ // Priced in the dashboard as GET /weather/:city
80
39
  app.get('/weather/:city', (req, res) => {
81
40
  res.json({ city: req.params.city, temperatureC: 21 });
82
41
  });
83
42
 
84
- await payments.ready(); // optional: fail at startup if the config cannot load
43
+ await payments.ready(); // fails at startup if the prices can't load
85
44
  app.listen(4021);
86
45
  ```
87
46
 
88
- How it works:
47
+ The middleware reloads your prices every minute. It fails closed, so a paid route is never served for free:
89
48
 
90
- - It loads `GET /x402/config` with your API key on the first request (or on `ready()`), then every minute.
91
- - It turns each resource into a stock `@x402/express` route: `METHOD /path` (or just `/path` for method `*`), the price in atomic units of the chosen asset, your `payTo`, and the token's EIP-712 domain in `extra`. A Permit2-only token gets `assetTransferMethod: 'permit2'` and EIP-2612 gas sponsoring.
92
- - Resources marked discoverable get the bazaar discovery extension, with their input and output schemas, when `@x402/extensions` is installed.
93
- - It rebuilds the stock middleware only when the routes change.
94
-
95
- It fails closed, so paid endpoints are never served for free:
96
-
97
- - If the first load fails, every request through the middleware answers `503` with `Retry-After` until a load succeeds. This covers a bad key, an account that is not active, or no payout address. Mount the middleware after your free routes.
98
- - If a refresh fails, the last good routes stay in use and a warning is logged.
49
+ - Until the first load succeeds, every request through it gets `503` with `Retry-After`. This happens with a bad key, an inactive account or no payout wallet.
50
+ - If a later reload fails, it keeps the last good prices and logs a warning.
99
51
 
100
52
  | Option | Default | |
101
53
  | --- | --- | --- |
102
- | `apiKey` | required | Same key as for `CryptonlyFacilitatorClient`. It also needs `x402.verify` for `GET /x402/config`. |
103
- | `sandbox`, `baseUrl` | production | As for `CryptonlyFacilitatorClient`. |
104
- | `refreshIntervalMs` | `60000` | How often to reload the configuration. `0` turns refreshing off. |
105
- | `schemes` | `[new ExactEvmScheme()]` | Scheme servers registered on the account's Base network. Resources with another scheme are skipped. |
106
- | `svmSchemes` | `[new ExactSvmScheme()]` when `@x402/svm` is installed, else none | Scheme servers registered on the account's Solana network. Without one, Solana-priced resources are skipped. |
54
+ | `apiKey` | required | Your Cryptonly API key. |
55
+ | `sandbox` | `false` | Use the sandbox. |
56
+ | `baseUrl` | production | Another API origin. Takes precedence over `sandbox`. |
57
+ | `refreshIntervalMs` | `60000` | How often to reload prices. `0` turns it off. |
58
+ | `retryAfterMs` | `5000` | After a failed first load, how long to answer `503` before the next try. |
59
+ | `schemes` | `[new ExactEvmScheme()]` | Schemes for Base. |
60
+ | `svmSchemes` | `[new ExactSvmScheme()]` if `@x402/svm` is installed | Schemes for Solana. |
107
61
  | `paywallConfig` | — | Passed to the stock `paymentMiddleware`. |
108
- | `logger` | `console` | Receives refresh failures and skipped resources. |
109
- | `createMiddleware` | stock `paymentMiddleware` | Builds the inner middleware for a set of routes, for example to add hooks. |
62
+ | `logger` | `console` | Gets reload failures and skipped routes. |
63
+ | `createMiddleware` | stock `paymentMiddleware` | Builds the inner middleware, for example to add hooks. |
110
64
 
111
- The returned middleware also has these methods:
65
+ The middleware also has `ready()`, `refresh()`, `routes()` and `close()`.
112
66
 
113
- - `ready()`: load now.
114
- - `refresh()`: reload now. It resolves `true` when the routes changed.
115
- - `routes()`: the routes in use.
116
- - `close()`: stop refreshing. The refresh timer is `unref()`ed and never keeps the process alive.
67
+ Using another framework? Build the routes with `fetchX402Config()` and `routesFromConfig()`, and pass them to its stock x402 middleware.
117
68
 
118
- For another framework, build the routes yourself with `fetchX402Config()` and `routesFromConfig()` from `@cryptonly/x402`, and pass them to its stock x402 middleware.
69
+ ## Prices in your code
119
70
 
120
- ### Discovery
121
-
122
- `CryptonlyFacilitatorClient` also sends the key on bazaar calls:
71
+ ```bash
72
+ npm install @cryptonly/x402 @x402/core @x402/express @x402/evm
73
+ ```
123
74
 
124
75
  ```ts
125
- import { withBazaar } from '@x402/extensions/bazaar';
126
-
127
- const client = withBazaar(new CryptonlyFacilitatorClient({ apiKey }));
128
- const { items } = await client.extensions.bazaar.listResources();
76
+ import { CryptonlyFacilitatorClient } from '@cryptonly/x402';
77
+ import { ExactEvmScheme } from '@x402/evm/exact/server';
78
+ import { paymentMiddleware, x402ResourceServer } from '@x402/express';
79
+
80
+ const facilitator = new CryptonlyFacilitatorClient({ apiKey: process.env.CRYPTONLY_API_KEY! });
81
+ const server = new x402ResourceServer(facilitator).register('eip155:8453', new ExactEvmScheme());
82
+
83
+ app.use(
84
+ paymentMiddleware(
85
+ {
86
+ 'GET /weather/:city': {
87
+ accepts: [{ scheme: 'exact', price: '$0.01', network: 'eip155:8453', payTo: process.env.PAY_TO! }],
88
+ },
89
+ },
90
+ server,
91
+ ),
92
+ );
129
93
  ```
130
94
 
131
- ## Networks and assets
95
+ `CryptonlyFacilitatorClient` takes `apiKey`, `sandbox` and `baseUrl`, as above. `payTo` must be a wallet you added in the dashboard.
96
+
97
+ ## Solana
98
+
99
+ Install `@x402/svm` and `@solana/kit`, and add a Solana payout wallet in the dashboard. With prices in your code, register `ExactSvmScheme` from `@x402/svm/exact/server` for `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`.
100
+
101
+ ## Sandbox
102
+
103
+ Pass `sandbox: true` and use a key from your [sandbox account](https://docs.cryptonly.net/guides/sandbox-environment/). The sandbox settles on Base Sepolia (`eip155:84532`) and Solana Devnet.
132
104
 
133
- Production settles on Base (`eip155:8453`) and Solana (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`); sandbox on Base Sepolia (`eip155:84532`) and Solana Devnet (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`). On Base, USDC and EURC settle with EIP-3009, and allowlisted tokens also through Permit2. On Solana, USDC and USDT settle with the `exact` SVM scheme: the buyer signs a token transfer and Cryptonly co-signs it as fee payer (`extra.feePayer` in `GET /x402/supported`). The buyer never needs ETH or SOL. `GET /x402/supported` lists what the facilitator accepts.
105
+ ## Learn more
134
106
 
135
- To take Solana payments with `cryptonlyPaymentMiddleware`, install `@x402/svm` and `@solana/kit` next to it and price resources in a Solana asset in the dashboard. Payouts are set up per network, so the account also needs a Solana `payTo`.
107
+ - [x402 quickstart](https://docs.cryptonly.net/guides/x402/quickstart/)
108
+ - [Discovery](https://docs.cryptonly.net/guides/x402/discovery/): list your endpoints for AI agents
109
+ - [Reference](https://docs.cryptonly.net/guides/x402/reference/): key scopes, limits and reason codes
136
110
 
137
- ## Settlement results
111
+ ## License
138
112
 
139
- USDC goes straight from the buyer to your `payTo` address; Cryptonly never holds it. If the transaction has not mined when `/settle` answers, the answer is `settlement_pending` with the transaction hash. List your settlements, including their final status, with `GET /x402/settlements` (scope `x402.list`) or `client.x402Settlements.list()` in `@cryptonly/sdk`.
113
+ [MIT](https://github.com/cryptonly-net/x402/blob/main/LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptonly/x402",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Cryptonly facilitator client and dashboard-configured payment middleware for the x402 protocol.",
5
5
  "license": "MIT",
6
6
  "private": false,