@pincerpay/merchant 0.2.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 (3) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +259 -233
  3. package/package.json +6 -6
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 PincerPay
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PincerPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,233 +1,259 @@
1
- # @pincerpay/merchant
2
-
3
- [![npm](https://img.shields.io/npm/v/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
4
- [![downloads](https://img.shields.io/npm/dm/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
5
- [![license](https://img.shields.io/npm/l/@pincerpay/merchant?style=flat-square)](https://github.com/ds1/pincerpay/blob/master/LICENSE)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
-
8
- Merchant SDK for accepting on-chain USDC payments from AI agents via the [x402 protocol](https://x402.org). Supports Express, Hono, and Next.js.
9
-
10
- > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
11
-
12
- ## Install
13
-
14
- ```bash
15
- npm install @pincerpay/merchant
16
- ```
17
-
18
- ## Quick Start
19
-
20
- ### Express
21
-
22
- ```typescript
23
- import express from "express";
24
- import { pincerpay } from "@pincerpay/merchant/express";
25
-
26
- const app = express();
27
-
28
- app.use(
29
- pincerpay({
30
- apiKey: process.env.PINCERPAY_API_KEY!,
31
- merchantAddress: "YOUR_SOLANA_ADDRESS",
32
- routes: {
33
- "GET /api/weather": {
34
- price: "0.01",
35
- chain: "solana",
36
- description: "Current weather data",
37
- },
38
- "POST /api/analyze": {
39
- price: "0.10",
40
- chains: ["solana", "base"],
41
- description: "AI text analysis",
42
- },
43
- },
44
- })
45
- );
46
-
47
- app.get("/api/weather", (req, res) => {
48
- res.json({ temp: 72, unit: "F" });
49
- });
50
-
51
- app.listen(3000);
52
- ```
53
-
54
- ### Hono
55
-
56
- ```typescript
57
- import { Hono } from "hono";
58
- import { pincerpayHono } from "@pincerpay/merchant/hono";
59
-
60
- const app = new Hono();
61
-
62
- app.use(
63
- "*",
64
- pincerpayHono({
65
- apiKey: process.env.PINCERPAY_API_KEY!,
66
- merchantAddress: "YOUR_SOLANA_ADDRESS",
67
- routes: {
68
- "GET /api/weather": {
69
- price: "0.01",
70
- chain: "solana",
71
- description: "Current weather data",
72
- },
73
- },
74
- })
75
- );
76
-
77
- app.get("/api/weather", (c) => c.json({ temp: 72 }));
78
-
79
- export default app;
80
- ```
81
-
82
- ### Next.js (Hono Adapter)
83
-
84
- Next.js doesn't have native x402 middleware support. Use Hono as a lightweight handler inside a catch-all App Router route:
85
-
86
- ```typescript
87
- // app/api/[...route]/route.ts
88
- import { Hono } from "hono";
89
- import { handle } from "hono/vercel";
90
- import { pincerpayHono } from "@pincerpay/merchant/hono";
91
-
92
- const app = new Hono().basePath("/api");
93
-
94
- app.use(
95
- "*",
96
- pincerpayHono({
97
- apiKey: process.env.PINCERPAY_API_KEY!,
98
- merchantAddress: "YOUR_SOLANA_ADDRESS",
99
- syncFacilitatorOnStart: false, // Avoids build-time network call during prerendering
100
- routes: {
101
- "GET /api/weather": {
102
- price: "0.01",
103
- chain: "solana",
104
- description: "Current weather data",
105
- },
106
- },
107
- })
108
- );
109
-
110
- app.get("/weather", (c) => c.json({ temp: 72 }));
111
-
112
- export const GET = handle(app);
113
- export const POST = handle(app);
114
- ```
115
-
116
- Install: `npm install @pincerpay/merchant hono`
117
-
118
- > **Note:** `basePath("/api")` must match the catch-all route location. Route handlers use paths relative to basePath (`/weather` serves `/api/weather`).
119
-
120
- ## API Reference
121
-
122
- ### `pincerpay(config): Express.RequestHandler`
123
-
124
- Express middleware that intercepts requests matching configured routes and returns HTTP 402 with x402 payment requirements.
125
-
126
- ### `pincerpayHono(config): HonoMiddleware`
127
-
128
- Hono middleware with identical behavior. Also used for Next.js via the Hono adapter pattern (see Next.js example above).
129
-
130
- ### `PincerPayClient`
131
-
132
- Low-level client for direct facilitator API access.
133
-
134
- ```typescript
135
- import { PincerPayClient } from "@pincerpay/merchant";
136
-
137
- const client = new PincerPayClient({
138
- apiKey: process.env.PINCERPAY_API_KEY!,
139
- merchantAddress: "YOUR_ADDRESS",
140
- facilitatorUrl: "https://facilitator.pincerpay.com", // default
141
- routes: {},
142
- });
143
-
144
- const result = await client.settle(paymentPayload, paymentRequirements);
145
- const status = await client.getStatus(txHash);
146
- const supported = await client.getSupported();
147
- ```
148
-
149
- ### Config
150
-
151
- ```typescript
152
- interface PincerPayConfig {
153
- apiKey: string;
154
- merchantAddress: string;
155
- facilitatorUrl?: string; // defaults to https://facilitator.pincerpay.com
156
- routes: Record<string, RoutePaywallConfig>;
157
- syncFacilitatorOnStart?: boolean; // defer facilitator sync to first request (default: false)
158
- }
159
-
160
- interface RoutePaywallConfig {
161
- price: string; // USDC amount (e.g., "0.01")
162
- chain?: string; // Chain shorthand (e.g., "solana", "base")
163
- chains?: string[]; // Multiple chains
164
- description?: string; // Human-readable description
165
- }
166
- ```
167
-
168
- ### Utility Functions
169
-
170
- ```typescript
171
- import { toBaseUnits, resolveRouteChains, getUsdcAsset } from "@pincerpay/merchant";
172
-
173
- toBaseUnits("0.01"); // "10000" (USDC has 6 decimals)
174
- toBaseUnits("1.00"); // "1000000"
175
-
176
- resolveRouteChains(routeConfig); // ["solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"]
177
-
178
- getUsdcAsset("solana-devnet"); // USDC mint address for Solana devnet
179
- getUsdcAsset("base"); // USDC contract address for Base
180
- ```
181
-
182
- ## Common Patterns
183
-
184
- ### Multi-chain pricing
185
-
186
- ```typescript
187
- pincerpay({
188
- apiKey: process.env.PINCERPAY_API_KEY!,
189
- merchantAddress: "YOUR_ADDRESS",
190
- routes: {
191
- "GET /api/data": {
192
- price: "0.05",
193
- chains: ["solana", "base", "polygon"],
194
- description: "Accept USDC on any supported chain",
195
- },
196
- },
197
- });
198
- ```
199
-
200
- ### Free routes alongside paid routes
201
-
202
- Routes not listed in `routes` pass through without payment. Only matching `METHOD /path` patterns trigger the 402 paywall.
203
-
204
- ```typescript
205
- pincerpay({
206
- apiKey: process.env.PINCERPAY_API_KEY!,
207
- merchantAddress: "YOUR_ADDRESS",
208
- routes: {
209
- "GET /api/premium": { price: "1.00", chain: "solana" },
210
- // GET /api/free is not listed -- no paywall
211
- },
212
- });
213
- ```
214
-
215
- ## Anti-Patterns
216
-
217
- ### Don't hardcode API keys
218
-
219
- ```typescript
220
- // Bad
221
- pincerpay({ apiKey: "pp_live_abc123...", ... });
222
-
223
- // Good
224
- pincerpay({ apiKey: process.env.PINCERPAY_API_KEY!, ... });
225
- ```
226
-
227
- ### Don't use the merchant SDK on the agent side
228
-
229
- The merchant SDK is for servers accepting payments. Agents should use `@pincerpay/agent` to make payments.
230
-
231
- ### Don't set price to "0"
232
-
233
- A price of "0" will still trigger the 402 flow. If a route should be free, omit it from the `routes` config.
1
+ # @pincerpay/merchant
2
+
3
+ [![npm](https://img.shields.io/npm/v/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
4
+ [![downloads](https://img.shields.io/npm/dm/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
5
+ [![license](https://img.shields.io/npm/l/@pincerpay/merchant?style=flat-square)](https://github.com/ds1/pincerpay/blob/master/LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+
8
+ Merchant SDK for accepting on-chain USDC payments from AI agents via the [x402 protocol](https://x402.org). Supports Express, Hono, and Next.js.
9
+
10
+ > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @pincerpay/merchant
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ### Express
21
+
22
+ ```typescript
23
+ import express from "express";
24
+ import { pincerpay } from "@pincerpay/merchant/express";
25
+
26
+ const app = express();
27
+
28
+ app.use(
29
+ pincerpay({
30
+ apiKey: process.env.PINCERPAY_API_KEY!,
31
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
32
+ routes: {
33
+ "GET /api/weather": {
34
+ price: "0.01",
35
+ chain: "solana",
36
+ description: "Current weather data",
37
+ },
38
+ "POST /api/analyze": {
39
+ price: "0.10",
40
+ chains: ["solana", "base"],
41
+ description: "AI text analysis",
42
+ },
43
+ },
44
+ })
45
+ );
46
+
47
+ app.get("/api/weather", (req, res) => {
48
+ res.json({ temp: 72, unit: "F" });
49
+ });
50
+
51
+ app.listen(3000);
52
+ ```
53
+
54
+ ### Hono
55
+
56
+ ```typescript
57
+ import { Hono } from "hono";
58
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
59
+
60
+ const app = new Hono();
61
+
62
+ app.use(
63
+ "*",
64
+ pincerpayHono({
65
+ apiKey: process.env.PINCERPAY_API_KEY!,
66
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
67
+ routes: {
68
+ "GET /api/weather": {
69
+ price: "0.01",
70
+ chain: "solana",
71
+ description: "Current weather data",
72
+ },
73
+ },
74
+ })
75
+ );
76
+
77
+ app.get("/api/weather", (c) => c.json({ temp: 72 }));
78
+
79
+ export default app;
80
+ ```
81
+
82
+ ### Next.js (Hono Adapter)
83
+
84
+ Next.js doesn't have native x402 middleware support. Use Hono as a lightweight handler inside a catch-all App Router route:
85
+
86
+ ```typescript
87
+ // app/api/[...route]/route.ts
88
+ import { Hono } from "hono";
89
+ import { handle } from "hono/vercel";
90
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
91
+
92
+ const app = new Hono().basePath("/api");
93
+
94
+ app.use(
95
+ "*",
96
+ pincerpayHono({
97
+ apiKey: process.env.PINCERPAY_API_KEY!,
98
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
99
+ syncFacilitatorOnStart: false, // Avoids build-time network call during prerendering
100
+ routes: {
101
+ "GET /api/weather": {
102
+ price: "0.01",
103
+ chain: "solana",
104
+ description: "Current weather data",
105
+ },
106
+ },
107
+ })
108
+ );
109
+
110
+ app.get("/weather", (c) => c.json({ temp: 72 }));
111
+
112
+ export const GET = handle(app);
113
+ export const POST = handle(app);
114
+ ```
115
+
116
+ Install: `npm install @pincerpay/merchant hono`
117
+
118
+ > **Note:** `basePath("/api")` must match the catch-all route location. Route handlers use paths relative to basePath (`/weather` serves `/api/weather`).
119
+
120
+ ## API Reference
121
+
122
+ ### `pincerpay(config): Express.RequestHandler`
123
+
124
+ Express middleware that intercepts requests matching configured routes and returns HTTP 402 with x402 payment requirements.
125
+
126
+ ### `pincerpayHono(config): HonoMiddleware`
127
+
128
+ Hono middleware with identical behavior. Also used for Next.js via the Hono adapter pattern (see Next.js example above).
129
+
130
+ ### `PincerPayClient`
131
+
132
+ Low-level client for direct facilitator API access.
133
+
134
+ ```typescript
135
+ import { PincerPayClient } from "@pincerpay/merchant";
136
+
137
+ const client = new PincerPayClient({
138
+ apiKey: process.env.PINCERPAY_API_KEY!,
139
+ merchantAddress: "YOUR_ADDRESS",
140
+ facilitatorUrl: "https://facilitator.pincerpay.com", // default
141
+ routes: {},
142
+ });
143
+
144
+ const result = await client.settle(paymentPayload, paymentRequirements);
145
+ const status = await client.getStatus(txHash);
146
+ const supported = await client.getSupported();
147
+ ```
148
+
149
+ ### Config
150
+
151
+ ```typescript
152
+ interface PincerPayConfig {
153
+ apiKey: string;
154
+ merchantAddress: string;
155
+ facilitatorUrl?: string; // defaults to https://facilitator.pincerpay.com
156
+ routes: Record<string, RoutePaywallConfig>;
157
+ syncFacilitatorOnStart?: boolean; // defer facilitator sync to first request (default: false)
158
+ }
159
+
160
+ interface RoutePaywallConfig {
161
+ price: string; // USDC amount (e.g., "0.01")
162
+ chain?: string; // Chain shorthand (e.g., "solana", "base")
163
+ chains?: string[]; // Multiple chains
164
+ description?: string; // Human-readable description
165
+ }
166
+ ```
167
+
168
+ ### Utility Functions
169
+
170
+ ```typescript
171
+ import { toBaseUnits, resolveRouteChains, getUsdcAsset } from "@pincerpay/merchant";
172
+
173
+ toBaseUnits("0.01"); // "10000" (USDC has 6 decimals)
174
+ toBaseUnits("1.00"); // "1000000"
175
+
176
+ resolveRouteChains(routeConfig); // ["solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"]
177
+
178
+ getUsdcAsset("solana-devnet"); // USDC mint address for Solana devnet
179
+ getUsdcAsset("base"); // USDC contract address for Base
180
+ ```
181
+
182
+ ## Common Patterns
183
+
184
+ ### Multi-chain pricing
185
+
186
+ ```typescript
187
+ pincerpay({
188
+ apiKey: process.env.PINCERPAY_API_KEY!,
189
+ merchantAddress: "YOUR_ADDRESS",
190
+ routes: {
191
+ "GET /api/data": {
192
+ price: "0.05",
193
+ chains: ["solana", "base", "polygon"],
194
+ description: "Accept USDC on any supported chain",
195
+ },
196
+ },
197
+ });
198
+ ```
199
+
200
+ ### Free routes alongside paid routes
201
+
202
+ Routes not listed in `routes` pass through without payment. Only matching `METHOD /path` patterns trigger the 402 paywall.
203
+
204
+ ```typescript
205
+ pincerpay({
206
+ apiKey: process.env.PINCERPAY_API_KEY!,
207
+ merchantAddress: "YOUR_ADDRESS",
208
+ routes: {
209
+ "GET /api/premium": { price: "1.00", chain: "solana" },
210
+ // GET /api/free is not listed -- no paywall
211
+ },
212
+ });
213
+ ```
214
+
215
+ ## Webhook Verification
216
+
217
+ PincerPay signs every webhook delivery with your webhook secret (HMAC-SHA256). Verify the `X-PincerPay-Signature` header to ensure requests are authentic:
218
+
219
+ ```typescript
220
+ import crypto from "node:crypto";
221
+
222
+ function verifyWebhook(payload: string, header: string, secret: string): boolean {
223
+ const parts = Object.fromEntries(
224
+ header.split(",").map((p) => p.split("=") as [string, string])
225
+ );
226
+ const age = Math.floor(Date.now() / 1000) - Number(parts.t);
227
+ if (age > 300) return false; // Reject replays > 5 min
228
+
229
+ const expected = crypto
230
+ .createHmac("sha256", secret)
231
+ .update(`${parts.t}.${payload}`)
232
+ .digest("hex");
233
+ return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
234
+ }
235
+ ```
236
+
237
+ Header format: `t=<unix-timestamp>,v1=<hmac-sha256-hex>`
238
+
239
+ Your webhook secret is in the [dashboard settings](https://www.pincerpay.com/dashboard/settings). See [full docs](https://www.pincerpay.com/docs/testing) for Python examples and Express integration patterns.
240
+
241
+ ## Anti-Patterns
242
+
243
+ ### Don't hardcode API keys
244
+
245
+ ```typescript
246
+ // Bad
247
+ pincerpay({ apiKey: "pp_live_abc123...", ... });
248
+
249
+ // Good
250
+ pincerpay({ apiKey: process.env.PINCERPAY_API_KEY!, ... });
251
+ ```
252
+
253
+ ### Don't use the merchant SDK on the agent side
254
+
255
+ The merchant SDK is for servers accepting payments. Agents should use `@pincerpay/agent` to make payments.
256
+
257
+ ### Don't set price to "0"
258
+
259
+ A price of "0" will still trigger the 402 flow. If a route should be free, omit it from the `routes` config.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pincerpay/merchant",
3
- "version": "0.2.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Merchant SDK for PincerPay. Express and Hono middleware for accepting USDC payments from AI agents.",
6
6
  "license": "MIT",
@@ -58,9 +58,9 @@
58
58
  }
59
59
  },
60
60
  "dependencies": {
61
- "@x402/core": "^2.3",
62
- "@x402/evm": "^2.3",
63
- "@x402/svm": "^2.3",
61
+ "@x402/core": "^2.6.0",
62
+ "@x402/evm": "^2.6.0",
63
+ "@x402/svm": "^2.6.0",
64
64
  "zod": "^3.24",
65
65
  "@pincerpay/core": "0.2.0"
66
66
  },
@@ -86,8 +86,8 @@
86
86
  },
87
87
  "devDependencies": {
88
88
  "@types/express": "^5",
89
- "@x402/express": "^2.3",
90
- "@x402/hono": "^2.3",
89
+ "@x402/express": "^2.6.0",
90
+ "@x402/hono": "^2.6.0",
91
91
  "express": "^5",
92
92
  "hono": "^4.12.0",
93
93
  "typescript": "^5.7"