@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.
- package/README.md +61 -87
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,60 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
# Cryptonly — x402 facilitator
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Accept x402 payments in Node.js, with Cryptonly as the facilitator.
|
|
8
8
|
|
|
9
|
-
[Website](https://cryptonly.net) · [Documentation](https://docs.cryptonly.net/
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(); //
|
|
43
|
+
await payments.ready(); // fails at startup if the prices can't load
|
|
85
44
|
app.listen(4021);
|
|
86
45
|
```
|
|
87
46
|
|
|
88
|
-
|
|
47
|
+
The middleware reloads your prices every minute. It fails closed, so a paid route is never served for free:
|
|
89
48
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
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 |
|
|
103
|
-
| `sandbox
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
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` |
|
|
109
|
-
| `createMiddleware` | stock `paymentMiddleware` | Builds the inner middleware
|
|
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
|
|
65
|
+
The middleware also has `ready()`, `refresh()`, `routes()` and `close()`.
|
|
112
66
|
|
|
113
|
-
|
|
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
|
-
|
|
69
|
+
## Prices in your code
|
|
119
70
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
71
|
+
```bash
|
|
72
|
+
npm install @cryptonly/x402 @x402/core @x402/express @x402/evm
|
|
73
|
+
```
|
|
123
74
|
|
|
124
75
|
```ts
|
|
125
|
-
import {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
+
## Learn more
|
|
134
106
|
|
|
135
|
-
|
|
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
|
-
##
|
|
111
|
+
## License
|
|
138
112
|
|
|
139
|
-
|
|
113
|
+
[MIT](https://github.com/cryptonly-net/x402/blob/main/LICENSE)
|