@devlab.group/agent-commerce 1.4.1 → 1.6.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.
Files changed (44) hide show
  1. package/README.md +168 -183
  2. package/dist/ap2.d.ts +21 -24
  3. package/dist/ap2.js +68 -82
  4. package/dist/ap2.js.map +1 -1
  5. package/dist/authorization-BpbWGGrf.d.ts +115 -0
  6. package/dist/{chunk-NWIQLJNU.js → chunk-74BSEXB5.js} +37 -34
  7. package/dist/chunk-74BSEXB5.js.map +1 -0
  8. package/dist/chunk-AFI2CEZS.js +10 -0
  9. package/dist/chunk-AFI2CEZS.js.map +1 -0
  10. package/dist/chunk-ATTWSFQP.js +680 -0
  11. package/dist/chunk-ATTWSFQP.js.map +1 -0
  12. package/dist/{chunk-ZEGFLRGV.js → chunk-IVJC5YLE.js} +63 -26
  13. package/dist/chunk-IVJC5YLE.js.map +1 -0
  14. package/dist/{chunk-GF6KHHKL.js → chunk-RAJGPGJG.js} +5 -8
  15. package/dist/chunk-RAJGPGJG.js.map +1 -0
  16. package/dist/chunk-V2V2E7HX.js +27 -0
  17. package/dist/chunk-V2V2E7HX.js.map +1 -0
  18. package/dist/cli/index.js +812 -573
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/constants-Bkq04FRZ.d.ts +48 -0
  21. package/dist/guardrails-71XwtXlT.d.ts +31 -0
  22. package/dist/index.d.ts +245 -265
  23. package/dist/index.js +1222 -626
  24. package/dist/index.js.map +1 -1
  25. package/dist/mcp.d.ts +6 -59
  26. package/dist/mcp.js +64 -53
  27. package/dist/mcp.js.map +1 -1
  28. package/dist/mpp.d.ts +50 -0
  29. package/dist/mpp.js +353 -0
  30. package/dist/mpp.js.map +1 -0
  31. package/dist/protocol-adapter-DTkrXTev.d.ts +238 -0
  32. package/dist/runtime-CiYbgGpi.d.ts +303 -0
  33. package/dist/{types-CJtwLu1c.d.ts → types-O6lg3Q5V.d.ts} +17 -23
  34. package/dist/x402.d.ts +43 -75
  35. package/dist/x402.js +13 -693
  36. package/dist/x402.js.map +1 -1
  37. package/package.json +13 -2
  38. package/dist/authorization-CPDcpJVa.d.ts +0 -123
  39. package/dist/chunk-GF6KHHKL.js.map +0 -1
  40. package/dist/chunk-NWIQLJNU.js.map +0 -1
  41. package/dist/chunk-ZEGFLRGV.js.map +0 -1
  42. package/dist/guardrails-Dmwi63KB.d.ts +0 -38
  43. package/dist/protocol-adapter-Bebmggf_.d.ts +0 -273
  44. package/dist/runtime-CKq3d_3K.d.ts +0 -340
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">Agent Commerce Gateway</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>One backend. Agent-commerce protocols on the front. No proprietary middleman.</strong>
4
+ <strong>One backend. Multiple agent-commerce protocols. Self-hosted and non-custodial.</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
@@ -10,6 +10,7 @@
10
10
  <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6">
11
11
  <img alt="MCP" src="https://img.shields.io/badge/MCP-supported-6b4fbb">
12
12
  <img alt="x402" src="https://img.shields.io/badge/x402-supported-0052ff">
13
+ <img alt="MPP" src="https://img.shields.io/badge/MPP-experimental-f0a30a">
13
14
  <img alt="A2A" src="https://img.shields.io/badge/A2A-experimental-f0a30a">
14
15
  <img alt="ACP" src="https://img.shields.io/badge/ACP-experimental-f0a30a">
15
16
  <img alt="AP2" src="https://img.shields.io/badge/AP2-experimental-f0a30a">
@@ -17,48 +18,48 @@
17
18
 
18
19
  ## What it is, in ten seconds
19
20
 
20
- You already have an HTTP API. AI agents want to **discover** it, **call** it and
21
- **pay** for it - over protocols you did not write and do not want to maintain.
21
+ You already have an HTTP API. Agent Commerce Gateway lets AI agents discover,
22
+ call and pay for it without adding those protocols to your backend.
22
23
 
23
- Agent Commerce Gateway sits in front of your existing API, in **your**
24
- infrastructure, and does that for you. You describe an endpoint in a YAML file -
25
- or generate that description from an OpenAPI document you already have - and
26
- agents get an MCP tool and an x402 paywall. Switch on the experimental adapters
27
- and the same resource is also an A2A skill, or an ACP checkout session. Switch
28
- on AP2 and a paid resource can also demand a signed mandate: proof the human
29
- behind the agent approved that exact purchase. The money goes straight to your
30
- wallet - the gateway never holds it, and never holds your keys.
24
+ Run the gateway in your infrastructure and describe each endpoint in YAML, or
25
+ generate draft resource definitions from OpenAPI. Resources can be exposed over
26
+ HTTP, MCP or experimental A2A; dedicated resources can implement experimental
27
+ ACP checkout operations. Paid resources use x402 or experimental MPP and can
28
+ also require an AP2 mandate proving that the buyer approved the purchase. Funds
29
+ go directly to the merchant wallet, and the gateway needs neither the buyer's
30
+ nor the merchant's private key.
31
31
 
32
32
  ```text
33
33
  Your existing API → Agent Commerce Gateway → AI Agent
34
- MCP · A2A · ACP · x402 · AP2 · receipts · doctor
34
+ MCP · A2A · ACP · x402 · MPP · AP2 · receipts · doctor
35
35
  ```
36
36
 
37
37
  ## Demo
38
38
 
39
39
  ```text
40
- [agent] Discovering resources over MCP...
41
- [agent] Found: market_report - Premium Market Report (0.01 USDC)
42
- [agent] Requesting resource...
43
-
44
- [gateway] Payment required: 0.01 USDC → 0x7099…79C8
45
- [buyer] Signing x402 authorisation...
46
- [gateway] Payment verified
47
- [gateway] Payment settled tx 0x4f2c…9ab1
48
- [gateway] Calling merchant backend...
49
- [gateway] Resource delivered
50
-
51
- [receipt] payment: settled
52
- [receipt] amount: 0.01 USDC
53
- [receipt] merchant: 0x7099…79C8
54
- [receipt] buyer balance 100.00 → 99.99 mUSDC
55
- [receipt] merchant balance 0.00 → 0.01 mUSDC
40
+ [agent] Agent Commerce Gateway: deterministic buyer demo
41
+ [buyer] balance before 100 MockUSDC
42
+ [agent] merchant balance before 0 MockUSDC
43
+ [gateway] connected to http://localhost:8080/mcp
44
+ [agent] discovered 2 tool(s): weather_basic, market_report
45
+ [agent] paid tool: "market_report", free tool: "weather_basic"
46
+ [gateway] 402 payment required: 0.01 USDC to 0x7099…79C8
47
+ [buyer] challenge checked before signing: pays 10000 units of 0x5fbd…0aa3 to 0x7099…79C8
48
+ [buyer] signed x402 payment proof (LOCAL DEVELOPMENT ONLY - DO NOT FUND)
49
+ [gateway] delivered "market_report"
50
+ [receipt] id=receipt_484b…1eba requestId=mcp_4292…c930 status=settled settlementTx=0x0b19…1c7f
51
+ [buyer] balance after 99.99 MockUSDC (Δ -0.01)
52
+ [agent] merchant balance after 0.01 MockUSDC (Δ 0.01)
53
+ [agent] on-chain balance changes match the expected payment amount
54
+ [gateway] delivered free tool "weather_basic": {"city":"Paris","temperatureC":-4,…}
55
+ [agent] demo complete: free and paid delivery both verified
56
56
  ```
57
57
 
58
- The dashboard at <http://localhost:5173> shows the same request as it happens.
59
- It polls the authenticated events route rather than streaming, because a browser
60
- cannot send the admin token over `EventSource`; see
61
- [why the stream is polled](SECURITY.md#the-live-event-stream-is-polled-not-streamed).
58
+ This excerpt of `npm run demo:agent` omits the address lines and shortens long
59
+ values. Balances, IDs and hashes differ from run to run.
60
+
61
+ The dashboard at <http://localhost:5173> polls the gateway's events route and
62
+ shows the same request within a few seconds.
62
63
 
63
64
  ## Install
64
65
 
@@ -68,21 +69,19 @@ npm install -g @devlab.group/agent-commerce # or install the `agent-commerce` bi
68
69
  agent-commerce doctor
69
70
  ```
70
71
 
71
- Requires **Node >= 22**. One package ships two things: the `agent-commerce`
72
- CLI (`init`, `validate`, `doctor`, `demo`) and a library for embedding the
73
- gateway in your own process. A default install is ~65 MB and pulls no
74
- blockchain or wallet dependencies at all - ~17 MB of that is the OpenAPI
75
- parser behind `import openapi`, which is a normal dependency because
76
- onboarding an existing API is the CLI's main job.
72
+ Requires **Node >= 22**. The package includes the `agent-commerce` CLI
73
+ (`init`, `validate`, `doctor`, `demo`, `import openapi`, `version`) and a library
74
+ for embedding the gateway.
75
+ The default install excludes optional protocol, payment and authorization
76
+ peers. The OpenAPI parser is a regular dependency because import is part of the
77
+ CLI.
77
78
 
78
79
  ```ts
79
80
  import { createGateway, loadConfig, receipts } from '@devlab.group/agent-commerce';
80
81
 
81
82
  const config = await loadConfig({ path: 'config.yaml' });
82
83
  const store = receipts({ path: './receipts.sqlite' });
83
- // Every ReceiptStore must be initialised before anything else touches it -
84
- // for the SQLite one this is where a schema written by a newer version is
85
- // caught, at boot rather than at the first query
84
+ // Initialize before use so an incompatible SQLite schema fails at startup
86
85
  await store.init();
87
86
 
88
87
  const gateway = await createGateway({
@@ -94,21 +93,23 @@ const gateway = await createGateway({
94
93
  const { url } = await gateway.listen();
95
94
  ```
96
95
 
97
- ### Optional peers - install only the rails you use
96
+ ### Optional peers
98
97
 
99
- The MCP adapter, the x402 provider and AP2 verification live on their own
100
- subpaths, because each needs a dependency the rest of the package does not -
101
- the x402 rail brings the whole EVM signing and RPC stack, which a gateway
102
- serving a free HTTP resource has no business installing.
98
+ Components with extra dependencies use separate subpaths, so a gateway serving
99
+ free HTTP resources does not install MCP, EVM, JOSE or SD-JWT packages.
103
100
 
104
101
  | You want | Install | Import |
105
102
  | --------------------------------------- | ---------------------------------- | ------------------------------------------ |
106
- | gateway, config, receipts, CLI | `@devlab.group/agent-commerce` | `from '@devlab.group/agent-commerce'` |
103
+ | gateway, config, receipts, A2A/ACP, CLI | `@devlab.group/agent-commerce` | `from '@devlab.group/agent-commerce'` |
107
104
  | expose resources as MCP tools | `+ @modelcontextprotocol/sdk` | `from '@devlab.group/agent-commerce/mcp'` |
108
105
  | accept x402 payments | `+ @x402/core @x402/evm viem` | `from '@devlab.group/agent-commerce/x402'` |
106
+ | accept MPP payments | `+ mppx viem @x402/core @x402/evm` | `from '@devlab.group/agent-commerce/mpp'` |
109
107
  | verify AP2 mandates, sign checkout JWTs | `+ jose @sd-jwt/core canonicalize` | `from '@devlab.group/agent-commerce/ap2'` |
110
108
  | authenticate to a CDP facilitator | `+ @coinbase/x402` | (no import - loaded on demand) |
111
109
 
110
+ MPP settles through an x402 facilitator, so its entry also needs the x402
111
+ peers.
112
+
112
113
  ```bash
113
114
  npm install @devlab.group/agent-commerce @modelcontextprotocol/sdk @x402/core @x402/evm viem
114
115
  ```
@@ -119,23 +120,17 @@ import { x402 } from '@devlab.group/agent-commerce/x402';
119
120
  import { ap2 } from '@devlab.group/agent-commerce/ap2';
120
121
  ```
121
122
 
122
- The AP2 three are small - about 1.3 MB installed between them, against roughly
123
- 63 MB for the x402 stack - but they stay optional on the same principle: a
124
- deployment that gates nothing on a mandate should not carry a JOSE stack and an
125
- SD-JWT parser to serve a resource.
123
+ AP2 peers remain optional because a deployment without mandate-gated resources
124
+ does not need JOSE or SD-JWT support.
126
125
 
127
126
  Peers are pinned exactly: x402's schemas and EIP-712 domains cross this
128
127
  boundary, so a version skew is a correctness problem rather than a convenience
129
- one. Import a subpath without its
130
- peer installed and Node fails at load naming the missing package - deliberately,
131
- rather than starting a gateway that silently serves nothing.
128
+ one. Importing a subpath without its peer fails at load time and names the
129
+ missing package.
132
130
 
133
- `@coinbase/x402` is the odd one out: it has no import of its own and is loaded
134
- dynamically, only when `facilitator.auth.type: cdp` is configured. It is worth
135
- avoiding if you can - it brings `@coinbase/cdp-sdk` and `axios`, which carry
136
- high-severity advisories, while the package itself and the other three peers
137
- audit clean. `auth.type: bearer` covers any facilitator with a static token and
138
- installs nothing.
131
+ `@coinbase/x402` has no subpath import. It is loaded dynamically only for
132
+ `facilitator.auth.type: cdp` and brings the larger CDP dependency tree. A
133
+ facilitator with a static token can use `auth.type: bearer` without it.
139
134
 
140
135
  ## Quickstart
141
136
 
@@ -155,15 +150,13 @@ npm run agent-commerce -- doctor --config config-demo.yaml # verify the whole st
155
150
  npm run demo:agent # watch an agent buy something
156
151
  ```
157
152
 
158
- <sub><b>Linux only</b>, and only if your user is not UID/GID 1000 (check with
159
- <code>id -u && id -g</code>): export <code>DOCKER_UID=$(id -u) DOCKER_GID=$(id -g)</code>
160
- before <code>docker compose up</code>. The chain-deploy step runs as that user so the
161
- deployment manifest it writes stays host-writable rather than root-owned. Docker
162
- Desktop on macOS and Windows translates permissions through its VM and does not
163
- need this.</sub>
153
+ <sub><b>Linux:</b> if your UID/GID is not 1000, export
154
+ <code>DOCKER_UID=$(id -u) DOCKER_GID=$(id -g)</code> before
155
+ <code>docker compose up</code>. This keeps the generated deployment manifest
156
+ host-writable. Docker Desktop does not need this.</sub>
164
157
 
165
- That is the whole thing. The stack is a private Anvil chain, a mock USDC token,
166
- a demo merchant API, the gateway and a dashboard - all local and disposable.
158
+ The disposable local stack includes Anvil, MockUSDC, a demo merchant API, the
159
+ gateway and a dashboard.
167
160
 
168
161
  To stop and wipe state: `docker compose down -v`.
169
162
 
@@ -174,7 +167,7 @@ To stop and wipe state: `docker compose down -v`.
174
167
  │ AI Agent │
175
168
  └───────────────────────────────────────┬──────────────────────────────────────┘
176
169
  │ MCP · A2A · ACP · HTTP
177
- │ PAYMENT-SIGNATURE
170
+ │ payment proof
178
171
  │ Agent-Authorization
179
172
  ┌───────────────────────────────────────▼──────────────────────────────────────┐
180
173
  │ Agent Commerce Gateway (yours) │
@@ -184,7 +177,7 @@ To stop and wipe state: `docker compose down -v`.
184
177
  │ ┌────────────────────┬──────────────┴──┬────────────────┐ │
185
178
  │ ▼ ▼ ▼ ▼ │
186
179
  │ AuthorizationProvider PaymentProvider BackendExecutor ReceiptStore │
187
- │ (ap2) (x402) (bounded HTTP) (SQLite) │
180
+ │ (ap2) (x402, mpp) (bounded HTTP) (SQLite) │
188
181
  └───────────────────────────────────────┬──────────────────────────────────────┘
189
182
  │
190
183
  ┌──────────▼─────────┐
@@ -192,11 +185,8 @@ To stop and wipe state: `docker compose down -v`.
192
185
  └────────────────────┘
193
186
  ```
194
187
 
195
- Every protocol adapter converges on **one execution pipeline**. That is what
196
- makes payment enforcement a property of the system rather than something each
197
- adapter has to remember. Money never passes through the box: the buyer pays the
198
- merchant directly on chain, and the gateway holds neither the funds nor a key.
199
- Full detail in [docs/architecture.md](docs/architecture.md).
188
+ Every protocol adapter uses one execution pipeline, so payment enforcement does
189
+ not depend on the adapter. See [Architecture](docs/architecture.md).
200
190
 
201
191
  ## Configure a resource
202
192
 
@@ -217,7 +207,7 @@ resources:
217
207
  payments: [x402]
218
208
  ```
219
209
 
220
- That is the integration. No SDK in your backend, no rewrite.
210
+ The gateway calls your existing backend, which needs no SDK or changes.
221
211
 
222
212
  ```bash
223
213
  npm run agent-commerce -- init # generate a config interactively
@@ -231,57 +221,58 @@ Already have an OpenAPI description? Generate the resources from it
231
221
  agent-commerce import openapi ./openapi.yaml
232
222
  ```
233
223
 
234
- It writes a reviewable `resources:` fragment - path, query and JSON body
235
- mapped, schemas converted to what the gateway actually enforces - and
236
- deliberately leaves `pricing` and `expose` out, because an OpenAPI document has
237
- no opinion on what an operation costs or who may see it. Credentials are never
238
- imported. See [OpenAPI import](docs/openapi-import.md) for the exact supported subset.
224
+ It writes a reviewable `resources:` fragment with path, query and JSON body
225
+ bindings and supported schemas. The source document never decides price or
226
+ exposure: `pricing` appears only with `--free` and `expose` only with
227
+ `--expose`, and credentials are never imported. See
228
+ [OpenAPI import](docs/openapi-import.md) for the supported subset.
239
229
 
240
230
  See [docs/configuration.md](docs/configuration.md).
241
231
 
242
232
  ## Protocol support
243
233
 
244
- | Protocol | Status | Pinned revision |
245
- | --------- | ------------ | -------------------------------------------------------- |
246
- | **MCP** | Supported | `@modelcontextprotocol/sdk@1.30.0` |
247
- | **x402** | Supported | x402 v2 (`@x402/core`, `@x402/evm`), scheme `exact`, EVM |
248
- | **HTTP** | Supported | native routes |
249
- | **A2A** | Experimental | A2A v1.0.0, binding `JSONRPC`, method `SendMessage` |
250
- | **ACP** | Experimental | ACP `2026-04-17`, REST checkout + discovery |
251
- | **AP2** | Experimental | AP2 `v0.2.0`, Direct Checkout Mandate verification |
252
- | UCP · MPP | Planned | - |
253
-
254
- [AP2](docs/ap2.md) is in that table because people look there, but it is an **authorization**
255
- method rather than a transport: it gates settlement on a resource that still
256
- takes a real payment, and it is the verifying half only - the gateway holds no
257
- signing key and issues no Checkout Receipt.
258
-
259
- "Planned" means **no code ships for it**. "Experimental" means the code ships,
260
- is tested against the protocol's own official artifacts, and serves a narrow
261
- named subset: [A2A](docs/protocols.md#a2a) and [ACP](docs/protocols.md#acp) are
262
- both off by default and documented in full there, as are
263
- [MCP](docs/protocols.md#mcp) and [x402](docs/protocols.md#x402). ACP serves the
264
- five stable checkout operations and advertises `services: ["checkout"]` and
265
- nothing more; its `payment_data` stays with the merchant's own checkout and is
266
- never turned into an x402 payment.
267
-
268
- Each adapter reports its own `supportedSpec`, `capabilities` and `unsupported`
269
- list at runtime through `GET /.well-known/agent-commerce` and
270
- `agent-commerce doctor`, so the claim is checkable rather than marketing.
234
+ | Protocol | Status | Pinned revision |
235
+ | -------- | ------------ | ------------------------------------------------------------------------- |
236
+ | **HTTP** | Supported | native routes |
237
+ | **MCP** | Supported | `@modelcontextprotocol/sdk@1.30.0` |
238
+ | **x402** | Supported | x402 v2 (`@x402/core`, `@x402/evm`), scheme `exact`, EVM |
239
+ | **MPP** | Experimental | `mppx@0.10.1`, `charge` + `evm` + EIP-3009, USDC on Base Sepolia and Base |
240
+ | **A2A** | Experimental | A2A v1.0.0, binding `JSONRPC`, method `SendMessage` |
241
+ | **ACP** | Experimental | ACP `2026-04-17`, REST checkout + discovery |
242
+ | **AP2** | Experimental | AP2 `v0.2.0`, Direct Checkout Mandate verification |
243
+ | UCP | Planned | no implementation |
244
+
245
+ [AP2](docs/ap2.md) is an authorization method, not a transport. It verifies a
246
+ mandate before a paid resource settles; the gateway does not issue the mandate
247
+ or its Checkout Receipt.
248
+
249
+ The experimental entries above ship off by default with documented subsets:
250
+ [A2A](docs/protocols.md#a2a), [ACP](docs/protocols.md#acp),
251
+ [AP2](docs/ap2.md#not-implemented) and [MPP](docs/protocols.md#mpp). Supported
252
+ [MCP](docs/protocols.md#mcp) and [x402](docs/protocols.md#x402) are also scoped.
253
+ ACP exposes only its five checkout operations; merchant `payment_data` is never
254
+ converted into a gateway payment proof.
255
+
256
+ `GET /.well-known/agent-commerce` reports `supportedSpec`, `capabilities` and
257
+ `unsupported` for registered adapters and providers. `agent-commerce doctor`
258
+ prints the `unsupported` lists for A2A, ACP and AP2 when they are enabled.
271
259
 
272
260
  ## Payment model
273
261
 
274
- - **Non-custodial.** The gateway never holds funds, and never asks for a
275
- merchant or buyer private key. `payTo` is your address.
262
+ - **Non-custodial.** Buyer payments go directly to the merchant address in
263
+ `payTo` (`recipient` for MPP). The gateway does not require buyer or merchant
264
+ private keys. Local facilitator mode does hold a separate gas-paying signer.
276
265
  - **Fail closed.** Missing, malformed, expired, replayed, wrong-amount,
277
- wrong-recipient, wrong-network and wrong-asset payments all fail - each with a
278
- test.
266
+ wrong-recipient, wrong-network and wrong-asset payments are rejected.
279
267
  - **Replay-safe twice over.** EIP-3009 stops a double spend on-chain; the
280
- gateway additionally reserves a `replayKey` derived from the authorisation
268
+ gateway additionally reserves a `replayKey` derived from the authorization
281
269
  before it settles anything.
282
- - **Real settlement in CI.** The end-to-end test asserts the buyer's balance
270
+ - **On-chain settlement in CI.** The end-to-end test asserts the buyer's balance
283
271
  falls and the merchant's rises by exactly the price, with a real transaction
284
272
  hash in the receipt. A log line saying "payment successful" would not count.
273
+ - **One selected rail per resource.** A resource can name several rails, such as
274
+ `payments: [x402, mpp]`; the first enabled one serves it, and nothing selects
275
+ or falls back between rails per request.
285
276
  - **Authorization is separate from payment.** A resource can also require an
286
277
  AP2 mandate, verified before settlement and spendable exactly once. It never
287
278
  moves money and never unlocks a resource on its own - the payment still has
@@ -289,50 +280,48 @@ list at runtime through `GET /.well-known/agent-commerce` and
289
280
 
290
281
  ## Public networks
291
282
 
292
- Same gateway, same pipeline - a different `network` and a facilitator that is
293
- not this process. No code changes, and no "live mode" to switch on.
283
+ Public networks use the same execution pipeline with a remote facilitator.
284
+ Choose the network in config; Base mainnet also requires `allowMainnet: true`.
294
285
 
295
286
  ### It has actually settled
296
287
 
297
- Not a roadmap entry. Both of these moved 0.01 USDC from a buyer to a merchant
298
- through a remote facilitator:
288
+ These transactions each moved 0.01 USDC from a buyer to a merchant through a
289
+ remote facilitator:
299
290
 
300
- | Network | Transaction |
301
- | ------------ | --------------------------------------------------------------------------------------------------------------------- |
302
- | Base Sepolia | [`0xea41b234c4…`](https://sepolia.basescan.org/tx/0xea41b234c4645a4d335589ec9753646aa7cccd1b97e9e15823b88bff7b54a247) |
303
- | Base | [`0x57ec81c2a3…`](https://basescan.org/tx/0x57ec81c2a360d14d59a43cf4e24be09a6bd75cbe6185016372895bda73e42763) |
291
+ | Rail | Network | Transaction |
292
+ | ---- | ------------ | --------------------------------------------------------------------------------------------------------------------- |
293
+ | x402 | Base Sepolia | [`0xea41b234c4…`](https://sepolia.basescan.org/tx/0xea41b234c4645a4d335589ec9753646aa7cccd1b97e9e15823b88bff7b54a247) |
294
+ | x402 | Base | [`0x57ec81c2a3…`](https://basescan.org/tx/0x57ec81c2a360d14d59a43cf4e24be09a6bd75cbe6185016372895bda73e42763) |
295
+ | MPP | Base Sepolia | [`0x5d9fcd111b…`](https://sepolia.basescan.org/tx/0x5d9fcd111b615bb8fc9e56d55096f119fc81c3c72c334f813cfaecee402d0ac3) |
296
+ | MPP | Base | [`0xf4255bd7ec…`](https://basescan.org/tx/0xf4255bd7ec46ed06505dedfb5f9537924bd2633816e7952ec6f2b468395b1087) |
304
297
 
305
- In both, the gateway held no key, signed nothing and paid no gas - the buyer
306
- signed an EIP-3009 authorisation offline holding no ETH, and the facilitator
307
- broadcast it. Each run reads the buyer and merchant balances and the
308
- transaction receipt back off the chain afterwards; the gateway's own report of
309
- success is not the proof.
298
+ The buyer signed each EIP-3009 authorization without ETH; the remote facilitator
299
+ paid gas and broadcast it. The gateway path received no buyer or merchant key.
300
+ The public-network smoke suites verify balance changes and fetch the transaction
301
+ receipt from the chain instead of trusting the gateway's response.
310
302
 
311
- Reproduce with `npm run test:testnet` / `npm run test:mainnet` - both spend
312
- real funds, skip themselves without credentials, and never run in CI.
303
+ Reproduce with `npm run test:testnet`, which spends test USDC, or
304
+ `npm run test:mainnet`, which spends real USDC. Both run only by hand; see
305
+ [Base mainnet](#base-mainnet).
313
306
 
314
307
  ### The facilitator model
315
308
 
316
- A **facilitator** verifies the buyer's authorisation and broadcasts the
317
- transfer. It is the only component that needs gas, and it is never this
318
- gateway on a public network.
309
+ A **facilitator** verifies the buyer's authorization and broadcasts the
310
+ transfer. It is the only component that needs gas.
319
311
 
320
- | `facilitator.mode` | Who signs | Where it is allowed |
321
- | ------------------ | ----------------------------------- | ------------------------ |
322
- | `local` | this process, with an Anvil dev key | the local dev chain only |
323
- | `remote` | an HTTP facilitator you point at | anywhere |
312
+ | `facilitator.mode` | Who signs | Where it is allowed |
313
+ | ------------------ | -------------------------------------- | ------------------------------------------------------------------ |
314
+ | `local` | this process, with a key you configure | a local Anvil chain; refused on mainnet, fails readiness elsewhere |
315
+ | `remote` | an HTTP facilitator you point at | anywhere |
324
316
 
325
- With `remote`, the gateway holds **no signing key at all**. The buyer signs an
326
- EIP-3009 authorisation offline - no ETH required - and the facilitator pays the
327
- gas. A facilitator cannot redirect your money: the authorisation names its
328
- recipient, amount and chain, so it can broadcast exactly that transfer or
329
- nothing. What it can do is see every authorisation you handle, and stop
330
- answering.
317
+ With `remote`, the gateway holds no facilitator signing key. The buyer signs an
318
+ EIP-3009 authorization without ETH, and the facilitator pays gas. Because the
319
+ authorization fixes the recipient, amount and chain, the facilitator cannot
320
+ redirect the transfer. It can see authorizations and refuse service.
331
321
 
332
- Three auth types: `none`, `bearer` (a static token, installs nothing) and `cdp`
333
- (Coinbase Developer Platform, which signs a fresh JWT per request). Anything
334
- else is refused at config load rather than sent nothing. You can also run your
335
- own - `remote` does not care who operates the endpoint.
322
+ Remote facilitator auth supports `none`, `bearer` and `cdp`. `cdp` loads the
323
+ optional peer `@coinbase/x402`, which signs a fresh JWT per request; bearer auth
324
+ needs no extra peer. Other types are rejected at config load.
336
325
 
337
326
  ### Base Sepolia
338
327
 
@@ -366,55 +355,51 @@ together, and reported by `doctor`, `health()` and `/.well-known`.
366
355
 
367
356
  ### Base mainnet
368
357
 
369
- Real funds, so nothing is defaulted. Every one of these is checked at config
370
- load, and the gateway will not start without them:
358
+ Mainnet moves real funds. Config validation requires:
371
359
 
372
- | Required | |
373
- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
374
- | `allowMainnet: true` | mainnet is never a default |
375
- | `facilitator.mode: remote` | `local` needs a funded gas key inside this process |
376
- | an HTTPS `facilitator.url` | |
377
- | `allowUnauthenticatedFacilitator: true` | only if that facilitator takes no credential |
378
- | a non-development `payTo` | |
379
- | `asset` = USDC on Base, `assetName: "USD Coin"` | **not** `"USDC"` - that deployment predates the rename, and the buyer signs the name into their EIP-712 domain |
360
+ | Required | |
361
+ | -------------------------------------------------------------- | -------------------------------------------------------------- |
362
+ | `allowMainnet: true` | mainnet is never a default |
363
+ | `facilitator.mode: remote` | `local` needs a funded gas key inside this process |
364
+ | an HTTPS `facilitator.url` | |
365
+ | `allowUnauthenticatedFacilitator: true` | required when `facilitator.auth.type` is `none` |
366
+ | a non-development destination (`payTo` or `recipient`) | |
367
+ | Base USDC with `assetName: "USD Coin"` and `assetVersion: "2"` | the buyer signs this EIP-712 domain; `"USDC"` is wrong on Base |
380
368
 
381
369
  Full config in [`examples/base-mainnet/`](examples/base-mainnet/), and
382
370
  [`examples/base-mainnet-payai/`](examples/base-mainnet-payai/) for an
383
- unauthenticated facilitator. `npm run test:mainnet` proves it end to end and
384
- spends real USDC on every run.
371
+ unauthenticated facilitator. The mainnet smoke suites cover x402 and MPP and
372
+ spend real USDC when their opt-ins and credentials are present.
385
373
 
386
374
  `agent-commerce validate` reports any of the above before anything starts, and
387
375
  `doctor` prints `LIVE MAINNET MODE - REAL FUNDS`.
388
376
 
389
- > Neither public-network suite runs in CI - there is no workflow and there must
390
- > not be one. A workflow means a funded key in repository secrets, spendable by
391
- > anyone with write access. Both suites run from the machine that holds the
392
- > wallet, and skip themselves without credentials.
377
+ > The public-network suites never run in CI, because a workflow would need a
378
+ > funded buyer key in repository secrets. Run them from the machine that holds
379
+ > the wallet. A test whose required settings are missing skips itself.
393
380
 
394
381
  ## Diagnostics
395
382
 
396
383
  ```console
397
384
  $ npm run agent-commerce -- doctor --config config-demo.yaml
398
385
 
399
- PASS Config valid - 2 resource(s), merchant "Demo Data Store" (using local chain manifest .deploy/local.json for X402_ASSET, X402_ASSET_NAME, X402_ASSET_VERSION, X402_ASSET_DECIMALS, MERCHANT_WALLET, X402_FACILITATOR_PRIVATE_KEY)
386
+ PASS Config valid: 2 resource(s), merchant "Demo Data Store" (using local chain manifest .deploy/local.json for X402_ASSET, X402_ASSET_NAME, X402_ASSET_VERSION, X402_ASSET_DECIMALS, MERCHANT_WALLET, X402_FACILITATOR_PRIVATE_KEY)
400
387
  PASS Gateway healthy and ready at http://127.0.0.1:8080
401
388
  PASS Backend 2/2 backend host(s) reachable
402
389
  PASS Protocols http=on mcp=on (/mcp) a2a=off acp=off
403
390
  INFO A2A disabled
404
391
  INFO ACP disabled
405
392
  INFO AP2 disabled
406
- PASS Payments x402 v2 (scheme=exact) enabled - LOCAL dev chain (eip155:84532, chain id shared with Base Sepolia), destination=0x7099…79C8, facilitator=local
407
- INFO Payments (MPP) planned - not implemented in this release
408
- PASS Storage sqlite schema v1 writable; receipts=2
393
+ PASS Payments x402 v2 (scheme=exact) enabled - LOCAL dev chain (eip155:84532, chain id shared with Base Sepolia), destination=0x7099…79C8, facilitator=local (in-process)
394
+ INFO Payments (MPP) MPP not configured
395
+ PASS Storage sqlite schema v2 writable; receipts=2
409
396
  PASS Protocol versions reported by gateway /.well-known/agent-commerce
410
397
 
411
398
  Score: 7/7 checks passed
412
399
  ```
413
400
 
414
- That is real output, not an illustration. `doctor` also cross-checks the
415
- gateway's *live* settlement configuration against what your local config
416
- resolves to, and fails if they disagree - a diagnostic that passes while the
417
- system is misconfigured is worse than none.
401
+ `doctor` cross-checks the gateway's live settlement configuration against the
402
+ resolved local config and fails if they differ.
418
403
 
419
404
  Exits non-zero if anything fails. `--json` for machines.
420
405
 
@@ -426,8 +411,8 @@ reachable by anyone else, know the split:
426
411
  - **Agent routes** (`/api/resources/:id/invoke`, `/mcp`, the A2A mount) are
427
412
  unauthenticated by design - paid resources are protected by payment, not by a
428
413
  password. ACP is the exception: its checkout routes require a bearer token.
429
- - **Operator routes** (`/api/receipts`, `/api/events`, `/api/events/stream`) are
430
- the merchant's commerce ledger: payer addresses, amounts, settlement hashes.
414
+ - **Operator routes** (`/api/receipts`, `/api/events`) are the merchant's
415
+ commerce ledger: payer addresses, amounts, settlement hashes.
431
416
  They require `server.adminToken`, and return **404** if none is configured.
432
417
  - **Browsers** are governed by `server.allowedOrigins`, an explicit allowlist
433
418
  that defaults to empty.
@@ -452,30 +437,30 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
452
437
  **Now** - MCP, x402 v2, settlement on the local chain, Base Sepolia and Base
453
438
  mainnet, receipts, doctor, deterministic demo, experimental A2A v1.0.0 and ACP
454
439
  `2026-04-17` checkout adapters, experimental AP2 v0.2.0 mandate verification,
455
- and experimental OpenAPI import.
440
+ experimental MPP `charge` payments, and experimental OpenAPI import.
456
441
 
457
- **Next** - a `doctor` GitHub Action · UCP · MPP · autonomous-mode AP2 (open
458
- mandates, agent key binding, constraint evaluation) · more of ACP (carts, feed,
459
- delegated payment) · Shopify and WooCommerce examples · PostgreSQL · richer
460
- observability · multi-file and remote OpenAPI sources.
442
+ **Next** - a `doctor` GitHub Action · UCP ·
443
+ autonomous-mode AP2 (open mandates, agent key binding, constraint evaluation) ·
444
+ more of ACP (carts, feed, delegated payment) · Shopify and WooCommerce examples ·
445
+ PostgreSQL · richer observability · multi-file and remote OpenAPI sources.
461
446
 
462
- New protocols land only after the adapter model survives real use. Scope
463
- discipline is a release requirement, not a mood.
447
+ New protocols need evidence that the adapter model works in real use before
448
+ they are added to a release.
464
449
 
465
450
  ## Documentation
466
451
 
467
452
  | | |
468
453
  | ---------------------------------------------- | ------------------------------------------- |
469
454
  | [Architecture](docs/architecture.md) | how the pieces fit |
470
- | [Payment flow](docs/payment-flow.md) | the paid round trip, and every way it fails |
471
- | [Protocols](docs/protocols.md) | exactly what is and is not supported |
455
+ | [Payment flow](docs/payment-flow.md) | the paid round trip and failure paths |
456
+ | [Protocols](docs/protocols.md) | supported and unsupported protocol features |
472
457
  | [AP2](docs/ap2.md) | mandate verification and the trust model |
473
458
  | [Configuration](docs/configuration.md) | `config.yaml` reference |
474
459
  | [OpenAPI import](docs/openapi-import.md) | generate resources from an existing API |
475
460
  | [Security model](docs/security.md) | trust boundaries, and what we do not defend |
476
- | [Contracts](docs/contracts.md) | the frozen cross-package contract |
461
+ | [Contracts](docs/contracts.md) | the frozen cross-area contract |
477
462
  | [Adapter guide](docs/contributing-adapters.md) | add a protocol or a payment rail |
478
463
 
479
- ## Licence
464
+ ## License
480
465
 
481
466
  [Apache-2.0](LICENSE).