aixyz 0.33.0 → 0.34.0
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/accepts.ts +38 -23
- package/app/index.ts +13 -7
- package/app/payment/payment.ts +30 -9
- package/app/plugin.ts +2 -3
- package/app/plugins/a2a.ts +1 -1
- package/app/plugins/index-page/index.ts +3 -2
- package/app/plugins/mcp.ts +33 -10
- package/app/types.ts +6 -2
- package/docs/api-reference/accepts.mdx +71 -5
- package/docs/api-reference/agent.mdx +1 -1
- package/docs/api-reference/tools.mdx +4 -4
- package/docs/getting-started/agent-and-tools.mdx +11 -0
- package/docs/getting-started/payments.mdx +31 -0
- package/package.json +4 -4
package/accepts.ts
CHANGED
|
@@ -1,32 +1,47 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { FacilitatorClient, HTTPFacilitatorClient } from "@x402/core/server";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
scheme: "exact";
|
|
8
|
-
price: string;
|
|
4
|
+
const AcceptsX402Scheme = z.object({
|
|
5
|
+
scheme: z.literal("exact"),
|
|
6
|
+
price: z.string(),
|
|
9
7
|
// TODO(kevin): update type to Network (`string:string`)
|
|
10
|
-
network
|
|
11
|
-
payTo
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
z.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
8
|
+
network: z.string().optional(),
|
|
9
|
+
payTo: z.string().optional(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/** Used for multiple accepts — explicit network is required to properly register schemes on the resource server. */
|
|
13
|
+
const AcceptsX402EntryScheme = z.object({
|
|
14
|
+
scheme: z.literal("exact"),
|
|
15
|
+
price: z.string(),
|
|
16
|
+
network: z.string(),
|
|
17
|
+
payTo: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const AcceptsFreeScheme = z.object({
|
|
21
|
+
scheme: z.literal("free"),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export type AcceptsX402 = z.infer<typeof AcceptsX402Scheme>;
|
|
25
|
+
export type AcceptsX402Entry = z.infer<typeof AcceptsX402EntryScheme>;
|
|
26
|
+
export type AcceptsX402Multi = AcceptsX402Entry[];
|
|
27
|
+
export type AcceptsFree = z.infer<typeof AcceptsFreeScheme>;
|
|
28
|
+
export type Accepts = AcceptsX402 | AcceptsFree | AcceptsX402Multi;
|
|
29
|
+
|
|
30
|
+
export const AcceptsScheme: z.ZodType<Accepts> = z.union([
|
|
31
|
+
z.discriminatedUnion("scheme", [AcceptsX402Scheme, AcceptsFreeScheme]),
|
|
32
|
+
z.array(AcceptsX402EntryScheme).min(1),
|
|
28
33
|
]);
|
|
29
34
|
|
|
35
|
+
export function normalizeAcceptsX402(accepts: AcceptsX402 | AcceptsX402Multi): AcceptsX402[] {
|
|
36
|
+
return Array.isArray(accepts) ? accepts : [accepts];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isAcceptsPaid(accepts: Accepts): accepts is AcceptsX402 | AcceptsX402Multi {
|
|
40
|
+
if (Array.isArray(accepts))
|
|
41
|
+
return accepts.length > 0 && accepts.every((e) => e.scheme === "exact" && typeof e.network === "string");
|
|
42
|
+
return accepts.scheme === "exact";
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
export type { FacilitatorClient };
|
|
31
46
|
|
|
32
47
|
export { HTTPFacilitatorClient };
|
package/app/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isAcceptsPaid, AcceptsScheme } from "../accepts";
|
|
2
|
+
import type { Accepts } from "../accepts";
|
|
2
3
|
import type { FacilitatorClient } from "@x402/core/server";
|
|
3
|
-
import { type HttpMethod, type RouteHandler, type Middleware, type RouteEntry } from "./types";
|
|
4
|
+
import { type HttpMethod, type RouteHandler, type Middleware, type RouteEntry, type RouteOptions } from "./types";
|
|
4
5
|
import { PaymentGateway } from "./payment/payment";
|
|
5
|
-
import { Network } from "@x402/core/types";
|
|
6
6
|
import { getAixyzConfig } from "@aixyz/config";
|
|
7
7
|
import { loadEnvConfig } from "@next/env";
|
|
8
8
|
import { BasePlugin, type RegisterContext, type InitializeContext } from "./plugin";
|
|
@@ -37,7 +37,6 @@ export class AixyzApp {
|
|
|
37
37
|
|
|
38
38
|
if (options?.facilitators) {
|
|
39
39
|
this.payment = new PaymentGateway(options.facilitators, config);
|
|
40
|
-
this.payment.register((config.x402.network as Network) ?? "eip155:8453");
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -87,14 +86,21 @@ export class AixyzApp {
|
|
|
87
86
|
return `${method} ${path}`;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
/** Register a route with an optional x402 payment requirement. */
|
|
91
|
-
route(method: HttpMethod, path: string, handler: RouteHandler, options?:
|
|
89
|
+
/** Register a route with an optional x402 payment requirement. Free accepts are filtered out. */
|
|
90
|
+
route(method: HttpMethod, path: string, handler: RouteHandler, options?: RouteOptions): void {
|
|
92
91
|
const key = this.getRouteKey(method, path);
|
|
92
|
+
if (options?.payment) {
|
|
93
|
+
const result = AcceptsScheme.safeParse(options.payment);
|
|
94
|
+
if (!result.success) {
|
|
95
|
+
throw new Error(`Invalid accepts config for route "${method} ${path}": ${result.error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const payment = options?.payment && isAcceptsPaid(options.payment) ? options.payment : undefined;
|
|
93
99
|
this.routes.set(key, {
|
|
94
100
|
method,
|
|
95
101
|
path,
|
|
96
102
|
handler,
|
|
97
|
-
payment
|
|
103
|
+
payment,
|
|
98
104
|
});
|
|
99
105
|
}
|
|
100
106
|
|
package/app/payment/payment.ts
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
type HTTPResponseInstructions,
|
|
9
9
|
} from "@x402/core/http";
|
|
10
10
|
import { ExactEvmScheme } from "@x402/evm/exact/server";
|
|
11
|
-
import type { AcceptsX402 } from "../../accepts";
|
|
11
|
+
import type { AcceptsX402, AcceptsX402Multi } from "../../accepts";
|
|
12
|
+
import { normalizeAcceptsX402 } from "../../accepts";
|
|
12
13
|
import { Network, PaymentPayload, PaymentRequirements } from "@x402/core/types";
|
|
13
14
|
import { AixyzConfig } from "@aixyz/config";
|
|
14
15
|
|
|
@@ -78,29 +79,49 @@ export class PaymentGateway {
|
|
|
78
79
|
/**
|
|
79
80
|
* Add a payment-gated route. Must be called before initialize().
|
|
80
81
|
*/
|
|
81
|
-
addRoute(method: string, path: string, accepts: AcceptsX402): void {
|
|
82
|
+
addRoute(method: string, path: string, accepts: AcceptsX402 | AcceptsX402Multi): void {
|
|
82
83
|
const pattern = this.getRouteKey(method, path);
|
|
84
|
+
const items = normalizeAcceptsX402(accepts);
|
|
83
85
|
this.pendingRoutes.set(pattern, {
|
|
84
|
-
accepts: {
|
|
85
|
-
scheme:
|
|
86
|
-
payTo:
|
|
87
|
-
price:
|
|
88
|
-
network: (
|
|
89
|
-
},
|
|
86
|
+
accepts: items.map((a) => ({
|
|
87
|
+
scheme: a.scheme,
|
|
88
|
+
payTo: a.payTo ?? this.config.x402.payTo,
|
|
89
|
+
price: a.price,
|
|
90
|
+
network: (a.network as Network) ?? (this.config.x402.network as Network),
|
|
91
|
+
})),
|
|
90
92
|
});
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
/**
|
|
94
|
-
* Initialize the payment gateway.
|
|
96
|
+
* Initialize the payment gateway. Registers all required network schemes
|
|
97
|
+
* from pending routes, then builds the x402HTTPResourceServer.
|
|
95
98
|
* Must be called after all routes are added.
|
|
96
99
|
*/
|
|
97
100
|
async initialize(): Promise<void> {
|
|
101
|
+
this.registerNetworksFromRoutes();
|
|
98
102
|
const routes: RoutesConfig =
|
|
99
103
|
this.pendingRoutes.size > 0 ? Object.fromEntries(this.pendingRoutes) : { "* /*": { accepts: [] } };
|
|
100
104
|
this.httpServer = new x402HTTPResourceServer(this.resourceServer, routes);
|
|
101
105
|
await this.httpServer.initialize();
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
private registerNetworksFromRoutes(): void {
|
|
109
|
+
const networks = new Set<Network>();
|
|
110
|
+
const defaultNetwork = (this.config.x402.network as Network) ?? ("eip155:8453" as Network);
|
|
111
|
+
networks.add(defaultNetwork);
|
|
112
|
+
|
|
113
|
+
for (const [, route] of this.pendingRoutes) {
|
|
114
|
+
const accepts = Array.isArray(route.accepts) ? route.accepts : [route.accepts];
|
|
115
|
+
for (const opt of accepts) {
|
|
116
|
+
if (opt.network) networks.add(opt.network as Network);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const network of networks) {
|
|
121
|
+
this.register(network);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
104
125
|
/**
|
|
105
126
|
* Verify payment for a request. Returns a 402 Response if payment is required/invalid,
|
|
106
127
|
* or null if the request is authorized to proceed.
|
package/app/plugin.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { HttpMethod, RouteHandler, RouteEntry, Middleware } from "./types";
|
|
2
|
-
import type { AcceptsX402 } from "../accepts";
|
|
1
|
+
import type { HttpMethod, RouteHandler, RouteEntry, RouteOptions, Middleware } from "./types";
|
|
3
2
|
import type { PaymentGateway } from "./payment/payment";
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -14,7 +13,7 @@ import type { PaymentGateway } from "./payment/payment";
|
|
|
14
13
|
*/
|
|
15
14
|
export interface RegisterContext {
|
|
16
15
|
/** Register a route on the application. Automatically tracked in `plugin.registeredRoutes`. */
|
|
17
|
-
route(method: HttpMethod, path: string, handler: RouteHandler, options?:
|
|
16
|
+
route(method: HttpMethod, path: string, handler: RouteHandler, options?: RouteOptions): void;
|
|
18
17
|
/** Append a middleware to the application's middleware chain. */
|
|
19
18
|
use(middleware: Middleware): void;
|
|
20
19
|
}
|
package/app/plugins/a2a.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { BasePlugin, type RegisterContext, type InitializeContext } from "../../plugin";
|
|
4
4
|
import type { MCPPlugin } from "../mcp";
|
|
5
5
|
import { renderHtml } from "./html";
|
|
6
|
+
import { isAcceptsPaid } from "../../../accepts";
|
|
6
7
|
|
|
7
8
|
export type AixyzConfigRuntime = ReturnType<typeof getAixyzConfigRuntime>;
|
|
8
9
|
|
|
@@ -141,7 +142,7 @@ export class IndexPagePlugin extends BasePlugin {
|
|
|
141
142
|
protocol: "a2a",
|
|
142
143
|
name,
|
|
143
144
|
path: entry.path,
|
|
144
|
-
paid: entry.payment
|
|
145
|
+
paid: !!entry.payment, // only set for paid routes (free accepts filtered in AixyzApp.route())
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
148
|
}
|
|
@@ -170,7 +171,7 @@ export class IndexPagePlugin extends BasePlugin {
|
|
|
170
171
|
name: tool.name,
|
|
171
172
|
path: "/mcp",
|
|
172
173
|
description: tool.tool.description,
|
|
173
|
-
paid: tool.accepts
|
|
174
|
+
paid: tool.accepts ? isAcceptsPaid(tool.accepts) : false,
|
|
174
175
|
inputSchema,
|
|
175
176
|
});
|
|
176
177
|
}
|
package/app/plugins/mcp.ts
CHANGED
|
@@ -4,9 +4,10 @@ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/
|
|
|
4
4
|
import { createPaymentWrapper } from "@x402/mcp";
|
|
5
5
|
import { BasePlugin, type RegisterContext, type InitializeContext } from "../plugin";
|
|
6
6
|
import type { Accepts } from "../../accepts";
|
|
7
|
-
import { AcceptsScheme } from "../../accepts";
|
|
7
|
+
import { AcceptsScheme, isAcceptsPaid, normalizeAcceptsX402 } from "../../accepts";
|
|
8
8
|
import { getAixyzConfig, getAixyzConfigRuntime } from "../../config";
|
|
9
9
|
import { Network } from "@x402/core/types";
|
|
10
|
+
import { ExactEvmScheme } from "@x402/evm/exact/server";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* MCP (Model Context Protocol) plugin. Collects tools and exposes them
|
|
@@ -83,21 +84,43 @@ export class MCPPlugin extends BasePlugin {
|
|
|
83
84
|
|
|
84
85
|
const config = getAixyzConfig();
|
|
85
86
|
const resourceServer = ctx.payment.resourceServer;
|
|
87
|
+
const defaultNetwork = (config.x402.network as Network) ?? ("eip155:8453" as Network);
|
|
88
|
+
|
|
89
|
+
// MCP payment operates via @x402/mcp wrappers independently of the HTTP payment
|
|
90
|
+
// middleware (PaymentGateway), so network schemes must be registered here separately.
|
|
91
|
+
// The default network is already registered by PaymentGateway.initialize() on the
|
|
92
|
+
// shared resourceServer — seed the set so we skip re-registering it.
|
|
93
|
+
const registeredNetworks = new Set<string>([defaultNetwork]);
|
|
94
|
+
for (const { accepts } of this.registeredTools) {
|
|
95
|
+
if (!accepts || !isAcceptsPaid(accepts)) continue;
|
|
96
|
+
for (const a of normalizeAcceptsX402(accepts)) {
|
|
97
|
+
const network = a.network ?? defaultNetwork;
|
|
98
|
+
if (!registeredNetworks.has(network)) {
|
|
99
|
+
registeredNetworks.add(network);
|
|
100
|
+
resourceServer.register(network as Network, new ExactEvmScheme());
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
86
104
|
|
|
87
105
|
for (const { name, accepts } of this.registeredTools) {
|
|
88
|
-
if (accepts
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
if (!accepts || !isAcceptsPaid(accepts)) continue;
|
|
107
|
+
|
|
108
|
+
const items = normalizeAcceptsX402(accepts);
|
|
109
|
+
const allReqs: Awaited<ReturnType<typeof resourceServer.buildPaymentRequirements>> = [];
|
|
110
|
+
for (const a of items) {
|
|
111
|
+
const reqs = await resourceServer.buildPaymentRequirements({
|
|
112
|
+
scheme: a.scheme,
|
|
113
|
+
payTo: a.payTo ?? config.x402.payTo,
|
|
114
|
+
price: a.price,
|
|
115
|
+
network: (a.network as Network) ?? defaultNetwork,
|
|
116
|
+
});
|
|
117
|
+
allReqs.push(...reqs);
|
|
118
|
+
}
|
|
96
119
|
|
|
97
120
|
this.paymentWrappers.set(
|
|
98
121
|
name,
|
|
99
122
|
createPaymentWrapper(resourceServer, {
|
|
100
|
-
accepts:
|
|
123
|
+
accepts: allReqs,
|
|
101
124
|
resource: { url: `mcp://tool/${name}` },
|
|
102
125
|
}),
|
|
103
126
|
);
|
package/app/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AcceptsX402 } from "../accepts";
|
|
1
|
+
import type { Accepts, AcceptsX402, AcceptsX402Multi } from "../accepts";
|
|
2
2
|
|
|
3
3
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
4
4
|
|
|
@@ -6,9 +6,13 @@ export type RouteHandler = (request: Request) => Response | Promise<Response>;
|
|
|
6
6
|
|
|
7
7
|
export type Middleware = (request: Request, next: () => Promise<Response>) => Response | Promise<Response>;
|
|
8
8
|
|
|
9
|
+
export interface RouteOptions {
|
|
10
|
+
payment?: Accepts;
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
export interface RouteEntry {
|
|
10
14
|
method: HttpMethod;
|
|
11
15
|
path: string;
|
|
12
16
|
handler: RouteHandler;
|
|
13
|
-
payment?: AcceptsX402;
|
|
17
|
+
payment?: AcceptsX402 | AcceptsX402Multi;
|
|
14
18
|
}
|
|
@@ -6,18 +6,18 @@ description: "Payment configuration types and facilitator client for x402 gating
|
|
|
6
6
|
Types and utilities for configuring x402 payment gating on agent and tool endpoints.
|
|
7
7
|
|
|
8
8
|
```typescript
|
|
9
|
-
import type { Accepts, AcceptsX402, AcceptsFree } from "aixyz/accepts";
|
|
10
|
-
import { HTTPFacilitatorClient, facilitator } from "aixyz/accepts";
|
|
9
|
+
import type { Accepts, AcceptsX402, AcceptsX402Entry, AcceptsX402Multi, AcceptsFree } from "aixyz/accepts";
|
|
10
|
+
import { HTTPFacilitatorClient, facilitator, normalizeAcceptsX402, isAcceptsPaid } from "aixyz/accepts";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Types
|
|
14
14
|
|
|
15
15
|
### `Accepts`
|
|
16
16
|
|
|
17
|
-
Union type for payment configuration:
|
|
17
|
+
Union type for payment configuration. Supports a single payment option, free access, or an array of payment options for multi-network support:
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
type Accepts = AcceptsX402 | AcceptsFree;
|
|
20
|
+
type Accepts = AcceptsX402 | AcceptsFree | AcceptsX402Multi;
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
### `AcceptsX402`
|
|
@@ -40,6 +40,34 @@ type AcceptsX402 = {
|
|
|
40
40
|
| `network` | `string` | No | CAIP-2 chain ID, overrides `x402.network` from config |
|
|
41
41
|
| `payTo` | `string` | No | EVM address to receive payment, overrides `x402.payTo` config |
|
|
42
42
|
|
|
43
|
+
### `AcceptsX402Entry`
|
|
44
|
+
|
|
45
|
+
A single payment option within a multi-accepts array. Same as `AcceptsX402` but `network` is **required** — the server needs an explicit network to register each payment scheme:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
type AcceptsX402Entry = {
|
|
49
|
+
scheme: "exact";
|
|
50
|
+
price: string;
|
|
51
|
+
network: string; // required
|
|
52
|
+
payTo?: string;
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Field | Type | Required | Description |
|
|
57
|
+
| --------- | -------- | -------- | ------------------------------------------------------------- |
|
|
58
|
+
| `scheme` | `string` | Yes | Must be `"exact"` |
|
|
59
|
+
| `price` | `string` | Yes | USD price string (e.g. `"$0.005"`) |
|
|
60
|
+
| `network` | `string` | Yes | CAIP-2 chain ID — required for multi-accepts |
|
|
61
|
+
| `payTo` | `string` | No | EVM address to receive payment, overrides `x402.payTo` config |
|
|
62
|
+
|
|
63
|
+
### `AcceptsX402Multi`
|
|
64
|
+
|
|
65
|
+
An array of payment entries, enabling multi-network support. Must contain at least one entry:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
type AcceptsX402Multi = AcceptsX402Entry[];
|
|
69
|
+
```
|
|
70
|
+
|
|
43
71
|
### `AcceptsFree`
|
|
44
72
|
|
|
45
73
|
No payment required:
|
|
@@ -52,6 +80,22 @@ type AcceptsFree = {
|
|
|
52
80
|
|
|
53
81
|
## Exports
|
|
54
82
|
|
|
83
|
+
### `normalizeAcceptsX402`
|
|
84
|
+
|
|
85
|
+
Converts a single or multi accepts value into a uniform array:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
function normalizeAcceptsX402(accepts: AcceptsX402 | AcceptsX402Multi): AcceptsX402[];
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `isAcceptsPaid`
|
|
92
|
+
|
|
93
|
+
Type guard that returns `true` if the accepts config requires payment (i.e., is not `{ scheme: "free" }`):
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
function isAcceptsPaid(accepts: Accepts): accepts is AcceptsX402 | AcceptsX402Multi;
|
|
97
|
+
```
|
|
98
|
+
|
|
55
99
|
### `HTTPFacilitatorClient`
|
|
56
100
|
|
|
57
101
|
Client for communicating with an x402 facilitator service. Re-exported from `@x402/core/server`.
|
|
@@ -74,12 +118,19 @@ import { facilitator } from "aixyz/accepts";
|
|
|
74
118
|
|
|
75
119
|
### `AcceptsScheme`
|
|
76
120
|
|
|
77
|
-
Zod schema for validating `Accepts` objects at runtime:
|
|
121
|
+
Zod schema for validating `Accepts` objects at runtime. Accepts a single object or an array of payment entries:
|
|
78
122
|
|
|
79
123
|
```typescript
|
|
80
124
|
import { AcceptsScheme } from "aixyz/accepts";
|
|
81
125
|
|
|
126
|
+
// Single accepts
|
|
82
127
|
AcceptsScheme.parse({ scheme: "exact", price: "$0.005" });
|
|
128
|
+
|
|
129
|
+
// Multiple accepts
|
|
130
|
+
AcceptsScheme.parse([
|
|
131
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:8453" },
|
|
132
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:84532" },
|
|
133
|
+
]);
|
|
83
134
|
```
|
|
84
135
|
|
|
85
136
|
## Usage
|
|
@@ -103,6 +154,21 @@ export const accepts: Accepts = {
|
|
|
103
154
|
};
|
|
104
155
|
```
|
|
105
156
|
|
|
157
|
+
### Multiple payment options
|
|
158
|
+
|
|
159
|
+
Accept payment across multiple networks by passing an array. Each entry requires an explicit `network`:
|
|
160
|
+
|
|
161
|
+
```typescript title="app/agent.ts"
|
|
162
|
+
import type { Accepts } from "aixyz/accepts";
|
|
163
|
+
|
|
164
|
+
export const accepts: Accepts = [
|
|
165
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:8453" },
|
|
166
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:84532" },
|
|
167
|
+
];
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
All referenced networks are automatically registered with the payment gateway during initialization — no manual setup required.
|
|
171
|
+
|
|
106
172
|
### Custom facilitator
|
|
107
173
|
|
|
108
174
|
Create `app/accepts.ts` to override the default facilitator:
|
|
@@ -38,7 +38,7 @@ export default new ToolLoopAgent({
|
|
|
38
38
|
| `accepts` | `Accepts` | No | Payment config — gates the A2A `/agent` route |
|
|
39
39
|
| `capabilities` | `Capabilities` | No | A2A capabilities — controls streaming and push notification support |
|
|
40
40
|
|
|
41
|
-
When `accepts` is exported, the `/agent` endpoint requires x402 payment. Without it, the agent is not registered on the A2A endpoint.
|
|
41
|
+
When `accepts` is exported, the `/agent` endpoint requires x402 payment. Without it, the agent is not registered on the A2A endpoint. `accepts` can also be an array of payment entries for [multi-network support](/getting-started/payments#multiple-payment-options).
|
|
42
42
|
|
|
43
43
|
## Capabilities
|
|
44
44
|
|
|
@@ -28,10 +28,10 @@ export default tool({
|
|
|
28
28
|
|
|
29
29
|
## Exports
|
|
30
30
|
|
|
31
|
-
| Export | Type | Required | Description
|
|
32
|
-
| --------- | --------- | -------- |
|
|
33
|
-
| `default` | `tool()` | Yes | The tool instance
|
|
34
|
-
| `accepts` | `Accepts` | No | Payment config — gates the tool on MCP `/mcp
|
|
31
|
+
| Export | Type | Required | Description |
|
|
32
|
+
| --------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
+
| `default` | `tool()` | Yes | The tool instance |
|
|
34
|
+
| `accepts` | `Accepts` | No | Payment config — gates the tool on MCP `/mcp`. Supports [array format](/getting-started/payments#multiple-payment-options) for multi-network |
|
|
35
35
|
|
|
36
36
|
## Conventions
|
|
37
37
|
|
|
@@ -43,6 +43,15 @@ The optional `accepts` named export controls [x402 payment](/getting-started/pay
|
|
|
43
43
|
- Agents **with** `accepts` are registered on payment-gated A2A endpoints
|
|
44
44
|
- Agents **without** `accepts` are not registered
|
|
45
45
|
|
|
46
|
+
You can also pass an array to accept payment on multiple networks:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
export const accepts: Accepts = [
|
|
50
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:8453" },
|
|
51
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:84532" },
|
|
52
|
+
];
|
|
53
|
+
```
|
|
54
|
+
|
|
46
55
|
### `capabilities` Export
|
|
47
56
|
|
|
48
57
|
The optional `capabilities` named export configures the A2A agent card's capabilities and controls how the executor runs your agent:
|
|
@@ -160,6 +169,8 @@ export const accepts: Accepts = { scheme: "exact", price: "$0.001" };
|
|
|
160
169
|
export default tool({ ... });
|
|
161
170
|
```
|
|
162
171
|
|
|
172
|
+
Tools also support [multiple payment options](/getting-started/payments#multiple-payment-options) via an array of accepts entries.
|
|
173
|
+
|
|
163
174
|
## Custom Server
|
|
164
175
|
|
|
165
176
|
For full control over endpoint registration and middleware, create `app/server.ts`. This overrides auto-generation entirely:
|
|
@@ -64,6 +64,37 @@ export const accepts: Accepts = {
|
|
|
64
64
|
- Tool `accepts` gates the tool on the MCP `/mcp` endpoint
|
|
65
65
|
- Agents and tools **without** `accepts` are not registered on protocol endpoints
|
|
66
66
|
|
|
67
|
+
## Multiple Payment Options
|
|
68
|
+
|
|
69
|
+
Accept payment across multiple networks by passing an array of payment entries. This lets clients pay on whichever network they prefer:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
export const accepts: Accepts = [
|
|
73
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:8453" }, // Base
|
|
74
|
+
{ scheme: "exact", price: "$0.005", network: "eip155:84532" }, // Base Sepolia
|
|
75
|
+
];
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
When using the array format, `network` is **required** on each entry so the server can register the correct payment scheme for each network.
|
|
79
|
+
|
|
80
|
+
All referenced networks are automatically discovered and registered during server initialization — no manual configuration needed beyond the `accepts` export.
|
|
81
|
+
|
|
82
|
+
This works for both agents and tools:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// app/agent.ts — multi-network agent pricing
|
|
86
|
+
export const accepts: Accepts = [
|
|
87
|
+
{ scheme: "exact", price: "$0.01", network: "eip155:8453" },
|
|
88
|
+
{ scheme: "exact", price: "$0.01", network: "eip155:1" },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
// app/tools/premium-search.ts — multi-network tool pricing
|
|
92
|
+
export const accepts: Accepts = [
|
|
93
|
+
{ scheme: "exact", price: "$0.001", network: "eip155:8453" },
|
|
94
|
+
{ scheme: "exact", price: "$0.001", network: "eip155:1" },
|
|
95
|
+
];
|
|
96
|
+
```
|
|
97
|
+
|
|
67
98
|
## Payment Networks
|
|
68
99
|
|
|
69
100
|
Configure the payment network in `aixyz.config.ts`:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aixyz",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Payment-native SDK for AI Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@a2a-js/sdk": "^0.3.10",
|
|
43
|
-
"@aixyz/cli": "0.
|
|
44
|
-
"@aixyz/config": "0.
|
|
45
|
-
"@aixyz/erc-8004": "0.
|
|
43
|
+
"@aixyz/cli": "0.34.0",
|
|
44
|
+
"@aixyz/config": "0.34.0",
|
|
45
|
+
"@aixyz/erc-8004": "0.34.0",
|
|
46
46
|
"@kitajs/html": "^4.2.13",
|
|
47
47
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
48
48
|
"@next/env": "^16.1.6",
|