x402-engineer 0.1.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 (38) hide show
  1. package/AGENT.md +102 -0
  2. package/README.md +43 -0
  3. package/dist/cli.cjs +137 -0
  4. package/package.json +51 -0
  5. package/skills/stellar-dev/SKILL.md +146 -0
  6. package/skills/stellar-dev/advanced-patterns.md +188 -0
  7. package/skills/stellar-dev/api-rpc-horizon.md +521 -0
  8. package/skills/stellar-dev/common-pitfalls.md +510 -0
  9. package/skills/stellar-dev/contracts-soroban.md +565 -0
  10. package/skills/stellar-dev/ecosystem.md +430 -0
  11. package/skills/stellar-dev/frontend-stellar-sdk.md +651 -0
  12. package/skills/stellar-dev/resources.md +306 -0
  13. package/skills/stellar-dev/security.md +491 -0
  14. package/skills/stellar-dev/standards-reference.md +94 -0
  15. package/skills/stellar-dev/stellar-assets.md +419 -0
  16. package/skills/stellar-dev/testing.md +786 -0
  17. package/skills/stellar-dev/zk-proofs.md +136 -0
  18. package/skills/x402-add-paywall/SKILL.md +208 -0
  19. package/skills/x402-add-paywall/references/patterns.md +132 -0
  20. package/skills/x402-debug/SKILL.md +92 -0
  21. package/skills/x402-debug/references/checklist.md +146 -0
  22. package/skills/x402-explain/SKILL.md +136 -0
  23. package/skills/x402-init/SKILL.md +129 -0
  24. package/skills/x402-init/templates/env-example.md +17 -0
  25. package/skills/x402-init/templates/express/config.ts.md +29 -0
  26. package/skills/x402-init/templates/express/server.ts.md +30 -0
  27. package/skills/x402-init/templates/fastify/adapter.ts.md +66 -0
  28. package/skills/x402-init/templates/fastify/config.ts.md +29 -0
  29. package/skills/x402-init/templates/fastify/server.ts.md +90 -0
  30. package/skills/x402-init/templates/hono/config.ts.md +29 -0
  31. package/skills/x402-init/templates/hono/server.ts.md +31 -0
  32. package/skills/x402-init/templates/next-app-router/config.ts.md +29 -0
  33. package/skills/x402-init/templates/next-app-router/server.ts.md +31 -0
  34. package/skills/x402-stellar/SKILL.md +139 -0
  35. package/skills/x402-stellar/references/api.md +237 -0
  36. package/skills/x402-stellar/references/patterns.md +276 -0
  37. package/skills/x402-stellar/references/setup.md +138 -0
  38. package/skills/x402-stellar/scripts/check-deps.js +218 -0
@@ -0,0 +1,146 @@
1
+ # x402 Debug Checklist
2
+
3
+ Comprehensive diagnostic checklist for `/x402:debug`. Run every check in order. Report results using `[PASS]`, `[FAIL]`, or `[WARN]` prefixes.
4
+
5
+ ## Category 1: Environment Variables
6
+
7
+ ### Check: SERVER_STELLAR_ADDRESS
8
+ - **How:** Read `.env.local` (or `.env`) and check for `SERVER_STELLAR_ADDRESS`
9
+ - **PASS:** Variable is set, value starts with `G`, length is 56 characters
10
+ - Output: `[PASS] SERVER_STELLAR_ADDRESS`
11
+ - **FAIL:** Variable not set or empty
12
+ - Output: `[FAIL] Environment variable SERVER_STELLAR_ADDRESS: Not set`
13
+ - Fix: `Add SERVER_STELLAR_ADDRESS to .env.local (see .env.example)`
14
+ - **WARN:** Variable is set but doesn't start with `G` or length is not 56
15
+ - Output: `[WARN] SERVER_STELLAR_ADDRESS: Value doesn't look like a Stellar public key (expected G... with 56 chars)`
16
+ - Fix: `Verify the key at https://laboratory.stellar.org`
17
+
18
+ ### Check: FACILITATOR_URL
19
+ - **How:** Read `.env.local` (or `.env`) and check for `FACILITATOR_URL`
20
+ - **PASS:** Variable is set and starts with `https://`
21
+ - Output: `[PASS] FACILITATOR_URL`
22
+ - **FAIL:** Variable not set or empty
23
+ - Output: `[FAIL] Environment variable FACILITATOR_URL: Not set`
24
+ - Fix: `Add FACILITATOR_URL to .env.local. Testnet: https://channels.openzeppelin.com/x402/testnet`
25
+ - **WARN:** Variable is set but doesn't start with `https://`
26
+ - Output: `[WARN] FACILITATOR_URL: Value doesn't look like a URL`
27
+ - Fix: `Expected format: https://channels.openzeppelin.com/x402/testnet`
28
+
29
+ ### Check: FACILITATOR_API_KEY
30
+ - **How:** Read `.env.local` (or `.env`) and check for `FACILITATOR_API_KEY`
31
+ - **PASS:** Variable is set and non-empty
32
+ - Output: `[PASS] FACILITATOR_API_KEY`
33
+ - **FAIL:** Variable not set or empty
34
+ - Output: `[FAIL] Environment variable FACILITATOR_API_KEY: Not set`
35
+ - Fix: `Add FACILITATOR_API_KEY to .env.local (see .env.example). Get a key at: https://channels.openzeppelin.com/testnet/gen`
36
+
37
+ ## Category 2: Dependencies
38
+
39
+ ### Check: @x402/core installed
40
+ - **How:** Read `package.json` and check `dependencies` for `@x402/core`
41
+ - **PASS:** Package found in dependencies
42
+ - Output: `[PASS] @x402/core: Installed`
43
+ - **FAIL:** Package not found
44
+ - Output: `[FAIL] Dependency @x402/core: Not installed`
45
+ - Fix: `Run npm install @x402/core`
46
+
47
+ ### Check: @x402/stellar installed
48
+ - **How:** Read `package.json` and check `dependencies` for `@x402/stellar`
49
+ - **PASS:** Package found in dependencies
50
+ - Output: `[PASS] @x402/stellar: Installed`
51
+ - **FAIL:** Package not found
52
+ - Output: `[FAIL] Dependency @x402/stellar: Not installed`
53
+ - Fix: `Run npm install @x402/stellar`
54
+
55
+ ### Check: Framework-specific x402 package
56
+ - **How:** Based on detected framework, check for the correct adapter package
57
+ - Next.js: check for `@x402/next` in dependencies
58
+ - Express: check for `@x402/express` in dependencies
59
+ - Fastify: skip (no official package -- uses @x402/core directly)
60
+ - Hono: check for `@x402/hono` in dependencies
61
+ - **PASS:** Framework adapter package installed (or Fastify which doesn't need one)
62
+ - Output: `[PASS] Framework adapter: {package} installed` or `[PASS] Framework adapter: Fastify uses @x402/core directly (no dedicated package needed)`
63
+ - **FAIL:** Framework adapter package missing
64
+ - Output: `[FAIL] Dependency {package}: Not installed`
65
+ - Fix: `Run npm install {package}`
66
+
67
+ ### Check: Dependency versions
68
+ - **How:** Read `node_modules/@x402/core/package.json` for version
69
+ - **PASS:** Version is 2.x
70
+ - Output: `[PASS] @x402/core version: {version}`
71
+ - **WARN:** Version is below 2.0
72
+ - Output: `[WARN] @x402/core version {version}: Consider upgrading to 2.x`
73
+ - Fix: `Run npm install @x402/core@latest`
74
+
75
+ ## Category 3: Code Structure
76
+
77
+ ### Check: Route config file exists
78
+ - **How:** Use Grep to find files containing `RoutesConfig` import
79
+ - **PASS:** At least one file found
80
+ - Output: `[PASS] Route config: {file path}`
81
+ - **FAIL:** No file found
82
+ - Output: `[FAIL] Route config: No routesConfig file found`
83
+ - Fix: `Run /x402:init to create route configuration`
84
+
85
+ ### Check: Server/middleware file exists
86
+ - **How:** Use Grep to find files importing from `@x402/core/server` or `@x402/express` or `@x402/hono` or `@x402/next`
87
+ - **PASS:** At least one file found
88
+ - Output: `[PASS] Server middleware: {file path}`
89
+ - **FAIL:** No file found
90
+ - Output: `[FAIL] Server middleware: No x402 server file found`
91
+ - Fix: `Run /x402:init to scaffold the server middleware`
92
+
93
+ ### Check: ExactStellarScheme import path
94
+ - **How:** Use Grep to find `ExactStellarScheme` imports
95
+ - **PASS:** Import path is `@x402/stellar/exact/server`
96
+ - Output: `[PASS] ExactStellarScheme: Correctly imported from server path`
97
+ - **WARN:** Import path is `@x402/stellar/exact/client` (wrong for server-side)
98
+ - Output: `[WARN] ExactStellarScheme: Imported from client path instead of server path`
99
+ - Fix: `Change import to: import { ExactStellarScheme } from "@x402/stellar/exact/server"`
100
+
101
+ ### Check: Protected endpoints in routesConfig
102
+ - **How:** Read routesConfig file, count entries (keys matching `"METHOD /path"` pattern)
103
+ - **PASS:** At least one route entry exists
104
+ - Output: `[PASS] Protected endpoints: {count} route(s) configured`
105
+ - **WARN:** routesConfig is empty (no entries)
106
+ - Output: `[WARN] No protected endpoints in routesConfig`
107
+ - Fix: `Run /x402:add-paywall to protect an endpoint`
108
+
109
+ ### Check: Price format
110
+ - **How:** Read routesConfig, check that price values start with `$`
111
+ - **PASS:** All prices start with `$`
112
+ - Output: `[PASS] Price format: All prices use $ prefix`
113
+ - **WARN:** Price without `$` prefix found
114
+ - Output: `[WARN] Price format: Found price without $ prefix`
115
+ - Fix: `Use "$0.001" format (dollar sign required)`
116
+
117
+ ## Category 4: Framework Detection
118
+
119
+ ### Check: Framework detected
120
+ - **How:** Read `package.json` dependencies for `next`, `express`, `fastify`, `hono`
121
+ - **PASS:** Exactly one supported framework detected
122
+ - Output: `[PASS] Framework detected: {name}`
123
+ - **WARN:** Multiple frameworks detected
124
+ - Output: `[WARN] Multiple frameworks detected: {list}. Using {primary} based on priority.`
125
+ - **FAIL:** No supported framework detected
126
+ - Output: `[FAIL] Framework: Could not detect framework from package.json`
127
+ - Fix: `Supported: Next.js, Express, Fastify, Hono`
128
+
129
+ ### Check: Adapter matches framework
130
+ - **How:** Cross-check detected framework with imports in server file
131
+ - Next.js should import from `@x402/next` or use `withPayment`/`withX402`
132
+ - Express should import from `@x402/express`
133
+ - Fastify should import from `@x402/core/server` with custom adapter
134
+ - Hono should import from `@x402/hono`
135
+ - **PASS:** Server file imports match detected framework
136
+ - Output: `[PASS] Adapter matches framework: {framework}`
137
+ - **WARN:** Mismatch between framework and adapter imports
138
+ - Output: `[WARN] Framework mismatch: Detected {framework} but server imports from {package}`
139
+ - Fix: `Re-run /x402:init to regenerate correct adapter`
140
+
141
+ ## Summary Format
142
+
143
+ After all checks, output a summary line:
144
+ - If any FAIL: `{N} passed, {N} failed, {N} warnings. Fix the FAIL items above to complete your x402 setup.`
145
+ - If no FAIL but has WARN: `{N} passed, {N} warnings. x402 is configured but review the warnings above.`
146
+ - If all PASS: `All checks passed. x402 is ready.`
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: x402-explain
3
+ description: Generate a human-readable explanation of how x402 payment protection is wired in the current project.
4
+ user-invocable: true
5
+ disable-model-invocation: true
6
+ allowed-tools: [Read, Grep, Glob]
7
+ ---
8
+
9
+ # /x402:explain
10
+
11
+ > I'll analyze your codebase and explain exactly how x402 payment protection is wired -- which endpoints are protected, what the payment flow looks like, and where everything is configured.
12
+
13
+ ## Instructions
14
+
15
+ Output is generated fresh on every invocation -- no caching. Read the codebase live to reflect its current state.
16
+
17
+ ### Step 1 -- Check for x402 setup
18
+
19
+ Use Grep to check if `@x402/core` exists in `package.json` dependencies.
20
+
21
+ If NOT found, output exactly:
22
+
23
+ "No x402 payment protection detected in this project. Run /x402:init to get started."
24
+
25
+ Then STOP. Do not proceed to further steps.
26
+
27
+ ### Step 2 -- Detect framework
28
+
29
+ Check `package.json` dependencies for:
30
+ - `"next"` -- Next.js
31
+ - `"express"` -- Express
32
+ - `"fastify"` -- Fastify
33
+ - `"hono"` -- Hono
34
+
35
+ If multiple frameworks detected, prefer: Next.js > Express > Fastify > Hono (by ecosystem size).
36
+
37
+ ### Step 3 -- Find configuration files
38
+
39
+ - Use Grep to find files containing `RoutesConfig` import -> this is the routesConfig file path
40
+ - Use Grep to find files containing `x402ResourceServer` or `paymentMiddleware` or `withPayment` or `withX402` -> this is the server/middleware file path
41
+ - Use Grep to find files containing `// x402: payment-protected endpoint` -> these are protected route file paths
42
+ - Read `.env.local` (or `.env` as fallback) for env var values. **Mask sensitive values:** show first 4 chars + `...` only. Never output full env var values.
43
+
44
+ ### Step 4 -- Read and analyze
45
+
46
+ - Read the routesConfig file and parse route entries
47
+ - For each route entry, extract: HTTP method, path, price, network, payTo address
48
+ - Mask payTo address: show first 4 chars + `...` + last 4 chars
49
+ - Read the server/middleware file to understand the adapter pattern being used
50
+ - Read protected route files (if any) to understand the wrapping pattern
51
+
52
+ ### Step 5 -- Generate output
53
+
54
+ Produce the following markdown output. Use these exact section headings:
55
+
56
+ ```markdown
57
+ ## x402 Payment Protection Overview
58
+
59
+ Framework: {detected framework}
60
+ Adapter: {package name} ({version if detectable from node_modules})
61
+ Network: {network from config, e.g., "stellar:testnet"}
62
+ Receiving address: {first 4 chars}...{last 4 chars}
63
+
64
+ ## Protected Endpoints
65
+
66
+ | Method | Path | Price | Asset | Network |
67
+ |--------|------|-------|-------|---------|
68
+ | GET | /api/content | $0.001 | USDC | stellar:testnet |
69
+ | ... | ... | ... | ... | ... |
70
+ ```
71
+
72
+ If no endpoints in routesConfig, output instead of the table:
73
+
74
+ "No endpoints currently protected. Run /x402:add-paywall to protect an endpoint."
75
+
76
+ ```markdown
77
+ ## Payment Flow
78
+
79
+ 1. **Client sends request** to a protected endpoint (no payment header)
80
+ 2. **Server returns HTTP 402** with payment requirements in response headers
81
+ 3. **Client signs a payment** using their Stellar wallet (USDC amount from routesConfig)
82
+ 4. **Client retries** the same request with `X-Payment` header containing the signed payment
83
+ 5. **Facilitator verifies** the payment signature and settles the transaction on Stellar
84
+ 6. **Server returns the resource** after facilitator confirms payment
85
+
86
+ ## Framework: {name}
87
+ ```
88
+
89
+ Include framework-specific description based on detected framework:
90
+
91
+ **For Next.js:**
92
+ ```
93
+ Adapter pattern: Inline handler wrapping with `withPayment()`/`withX402()`
94
+ Each route handler is individually wrapped in its `route.ts` file.
95
+ ```
96
+
97
+ **For Express:**
98
+ ```
99
+ Adapter pattern: Global middleware via `paymentMiddleware()` from `@x402/express`
100
+ All routes in routesConfig are automatically protected.
101
+ ```
102
+
103
+ **For Fastify:**
104
+ ```
105
+ Adapter pattern: Fastify plugin via custom `x402PaymentPlugin` using `@x402/core`
106
+ All routes in routesConfig are automatically protected via onRequest hook.
107
+ Note: Uses custom FastifyAdapter because @x402/fastify is not yet published on npm.
108
+ ```
109
+
110
+ **For Hono:**
111
+ ```
112
+ Adapter pattern: Global middleware via `paymentMiddleware()` from `@x402/hono`
113
+ All routes in routesConfig are automatically protected.
114
+ ```
115
+
116
+ ```markdown
117
+ ## Configuration Files
118
+
119
+ | File | Purpose |
120
+ |------|---------|
121
+ | {config path} | Route pricing and environment configuration |
122
+ | {server path} | x402 middleware/adapter setup |
123
+ | .env.local | Environment variables (Stellar address, facilitator URL, API key) |
124
+ ```
125
+
126
+ If Fastify is detected, add an additional row:
127
+ ```
128
+ | {adapter path} | HTTPAdapter implementation (Fastify only) |
129
+ ```
130
+
131
+ ## Important Notes
132
+
133
+ - The Payment Flow section is always the same 6-step list (from protocol spec, not derived from codebase analysis).
134
+ - Mask all sensitive values: env vars show first 4 chars + `...`, Stellar addresses show first 4 chars + `...` + last 4 chars.
135
+ - Output sections must follow the exact headings above (`## x402 Payment Protection Overview`, `## Protected Endpoints`, `## Payment Flow`, `## Framework: {name}`, `## Configuration Files`).
136
+ - This command is read-only. Do not modify any files. Use only Read, Grep, and Glob tools.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: x402-init
3
+ description: Bootstrap x402 payment protection in a project. Detects framework, installs dependencies, creates config files, and scaffolds adapter.
4
+ user-invocable: true
5
+ disable-model-invocation: true
6
+ argument-hint: "[framework]"
7
+ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob]
8
+ ---
9
+
10
+ # /x402:init
11
+
12
+ > Bootstrap x402 payment protection in your project. I'll detect your framework, install the right packages, and scaffold all config files.
13
+
14
+ ## Important Rules
15
+
16
+ - Do NOT install `@x402/fastify` -- it does not exist on npm. For Fastify, use `@x402/core` directly with a custom adapter.
17
+ - Server-side `ExactStellarScheme` import path is always `@x402/stellar/exact/server` (NOT `@x402/stellar/exact/client`).
18
+ - All templates are in this skill's `templates/` directory. Read the template file and use its content as the basis for generated code.
19
+ - Adapt import paths if needed based on project structure (e.g., relative paths based on file placement).
20
+
21
+ ## Step 1 -- Check for Existing x402 Setup (Idempotency)
22
+
23
+ Before creating anything, check if x402 is already configured:
24
+
25
+ 1. **Check dependencies:** Use Grep to search for `@x402/core` in `package.json` dependencies
26
+ 2. **Check route config:** Use Glob to find files, then Grep to search for files containing a `RoutesConfig` import from `@x402/core/server`
27
+ 3. **Check env template:** Use Read to check if `.env.example` already contains `SERVER_STELLAR_ADDRESS`
28
+
29
+ **If all 3 exist:**
30
+ Output: `"x402 is already set up. {N} files exist, {N} skipped. Run /x402:debug to verify configuration."`
31
+ STOP -- do not create or modify any files.
32
+
33
+ **If some exist:**
34
+ Report which pieces are already present. Skip those. Only create the missing pieces. Continue to the relevant steps below, skipping steps for components that already exist.
35
+
36
+ ## Step 2 -- Detect Framework
37
+
38
+ **If `$ARGUMENTS` is provided** (e.g., `/x402:init express`), use that framework directly. Skip detection.
39
+
40
+ **Otherwise, detect from `package.json`:**
41
+
42
+ 1. Read `package.json` in the current working directory
43
+ 2. If no `package.json` in the current directory, walk up parent directories to find the nearest one
44
+ 3. Check the `dependencies` object (not `devDependencies`) for framework packages
45
+ 4. Detection heuristics -- priority: Next.js > Express > Fastify > Hono (if multiple found, use the first match):
46
+ - `"next"` in dependencies -> **Next.js App Router**
47
+ - `"express"` in dependencies -> **Express**
48
+ - `"fastify"` in dependencies -> **Fastify**
49
+ - `"hono"` in dependencies -> **Hono**
50
+
51
+ **Edge cases:**
52
+ - If `@nestjs/core` is found in dependencies, warn: `"NestJS detected, using underlying Express/Fastify adapter"` and detect which underlying framework NestJS uses (check for `@nestjs/platform-express` or `@nestjs/platform-fastify`)
53
+ - If no supported framework is detected, output: `"Could not detect framework from package.json. Supported: Next.js, Express, Fastify, Hono."` and STOP
54
+
55
+ ## Step 3 -- Detect Project Structure
56
+
57
+ Determine where to place x402 files based on existing project conventions:
58
+
59
+ 1. Check if the project uses a `src/` directory pattern (e.g., `src/lib/`, `src/app/`, or other code under `src/`)
60
+ 2. If `src/` exists and contains code files: place x402 files in `src/lib/x402/`
61
+ 3. If no `src/` directory: place x402 files in `lib/x402/`
62
+ 4. For Next.js specifically: check for `app/` directory to confirm App Router usage
63
+
64
+ Store the base directory (`src/lib` or `lib`) for use in subsequent steps.
65
+
66
+ ## Step 4 -- Install Dependencies
67
+
68
+ Output: `"Installing @x402/core and @x402/stellar..."`
69
+
70
+ Run the framework-specific install command via Bash:
71
+
72
+ | Framework | Install Command |
73
+ |-----------|----------------|
74
+ | Next.js | `npm install @x402/next @x402/core @x402/stellar` |
75
+ | Express | `npm install @x402/express @x402/core @x402/stellar` |
76
+ | Fastify | `npm install @x402/core @x402/stellar` |
77
+ | Hono | `npm install @x402/hono @x402/core @x402/stellar` |
78
+
79
+ **Fastify note:** Do NOT install `@x402/fastify` -- it does not exist on npm. Only `@x402/core` and `@x402/stellar` are needed. The custom adapter code is scaffolded in Step 6.
80
+
81
+ ## Step 5 -- Scaffold Config Files
82
+
83
+ 1. Read the appropriate config template: `templates/{framework}/config.ts.md`
84
+ - Where `{framework}` is `next-app-router`, `express`, `fastify`, or `hono`
85
+ 2. Extract the TypeScript code from the template's fenced code block
86
+ 3. Write to `{base_dir}/x402/config.ts` (where `base_dir` was determined in Step 3)
87
+
88
+ 4. Read `templates/env-example.md`
89
+ 5. Extract the env content from the template's fenced code block
90
+ 6. Check if `.env.example` already exists at the project root:
91
+ - If it does NOT exist: create `.env.example` with the template content
92
+ - If it DOES exist: check if it already contains `SERVER_STELLAR_ADDRESS`. If not, append the x402 section to the existing file
93
+ 7. Output: `"Created .env.example with required variables. Copy to .env.local and fill in your values."`
94
+
95
+ ## Step 6 -- Scaffold Server/Middleware Files
96
+
97
+ 1. Read the appropriate server template: `templates/{framework}/server.ts.md`
98
+ 2. Extract the TypeScript code from the template's fenced code block
99
+ 3. Write to `{base_dir}/x402/server.ts`
100
+
101
+ **For Fastify only -- also scaffold the adapter:**
102
+ 4. Read `templates/fastify/adapter.ts.md`
103
+ 5. Extract the TypeScript code from the template's fenced code block
104
+ 6. Write to `{base_dir}/x402/adapter.ts`
105
+
106
+ ## Step 7 -- Summary
107
+
108
+ Count the files created during this run and output:
109
+
110
+ `"x402 initialized. Created {N} files: {file list}"`
111
+
112
+ List each file with its relative path from the project root, for example:
113
+
114
+ ```
115
+ x402 initialized. Created 3 files:
116
+ - lib/x402/config.ts
117
+ - lib/x402/server.ts
118
+ - .env.example
119
+ ```
120
+
121
+ For Fastify projects, the adapter file is also listed:
122
+
123
+ ```
124
+ x402 initialized. Created 4 files:
125
+ - lib/x402/config.ts
126
+ - lib/x402/server.ts
127
+ - lib/x402/adapter.ts
128
+ - .env.example
129
+ ```
@@ -0,0 +1,17 @@
1
+ # .env.example Template
2
+
3
+ ```env
4
+ # x402 Payment Configuration
5
+ # See: https://docs.x402.org/getting-started/quickstart-for-sellers
6
+
7
+ # Stellar public key (G...) that receives USDC payments
8
+ SERVER_STELLAR_ADDRESS=
9
+
10
+ # OpenZeppelin facilitator endpoint
11
+ # Testnet: https://channels.openzeppelin.com/x402/testnet
12
+ # Mainnet: https://channels.openzeppelin.com/x402/mainnet
13
+ FACILITATOR_URL=https://channels.openzeppelin.com/x402/testnet
14
+
15
+ # API key from https://channels.openzeppelin.com/testnet/gen
16
+ FACILITATOR_API_KEY=
17
+ ```
@@ -0,0 +1,29 @@
1
+ # Route Config Template
2
+
3
+ ```typescript
4
+ import type { RoutesConfig } from "@x402/core/server";
5
+
6
+ export const SERVER_ADDRESS = process.env.SERVER_STELLAR_ADDRESS!;
7
+ export const FACILITATOR_URL =
8
+ process.env.FACILITATOR_URL ||
9
+ "https://channels.openzeppelin.com/x402/testnet";
10
+ export const FACILITATOR_API_KEY = process.env.FACILITATOR_API_KEY!;
11
+
12
+ export const PRICE = "$0.001";
13
+ export const NETWORK = "stellar:testnet";
14
+
15
+ export const routesConfig: RoutesConfig = {
16
+ // "GET /api/example": {
17
+ // accepts: [
18
+ // {
19
+ // scheme: "exact",
20
+ // price: PRICE,
21
+ // network: NETWORK,
22
+ // payTo: SERVER_ADDRESS,
23
+ // },
24
+ // ],
25
+ // description: "Example protected endpoint",
26
+ // mimeType: "application/json",
27
+ // },
28
+ };
29
+ ```
@@ -0,0 +1,30 @@
1
+ # Express Server Template
2
+
3
+ Uses the official `@x402/express` package with `paymentMiddleware`.
4
+
5
+ ```typescript
6
+ import { paymentMiddleware, x402ResourceServer } from "@x402/express";
7
+ import { ExactStellarScheme } from "@x402/stellar/exact/server";
8
+ import { HTTPFacilitatorClient } from "@x402/core/server";
9
+ import {
10
+ routesConfig,
11
+ FACILITATOR_URL,
12
+ FACILITATOR_API_KEY,
13
+ NETWORK,
14
+ } from "./config";
15
+
16
+ const facilitatorClient = new HTTPFacilitatorClient({
17
+ url: FACILITATOR_URL,
18
+ createAuthHeaders: async () => {
19
+ const headers = { Authorization: `Bearer ${FACILITATOR_API_KEY}` };
20
+ return { verify: headers, settle: headers, supported: headers };
21
+ },
22
+ });
23
+
24
+ const resourceServer = new x402ResourceServer(facilitatorClient).register(
25
+ NETWORK,
26
+ new ExactStellarScheme()
27
+ );
28
+
29
+ export const x402Middleware = paymentMiddleware(routesConfig, resourceServer);
30
+ ```
@@ -0,0 +1,66 @@
1
+ # Fastify HTTPAdapter Template
2
+
3
+ Custom adapter implementing `HTTPAdapter` from `@x402/core/server`.
4
+ Required because `@x402/fastify` is not published on npm.
5
+
6
+ ```typescript
7
+ import type { HTTPAdapter } from "@x402/core/server";
8
+ import type { FastifyRequest } from "fastify";
9
+
10
+ export class FastifyAdapter implements HTTPAdapter {
11
+ constructor(private req: FastifyRequest) {}
12
+
13
+ getHeader(name: string): string | undefined {
14
+ const value = this.req.headers[name.toLowerCase()];
15
+ return Array.isArray(value) ? value[0] : value ?? undefined;
16
+ }
17
+
18
+ getMethod(): string {
19
+ return this.req.method;
20
+ }
21
+
22
+ getPath(): string {
23
+ return this.req.url.split("?")[0];
24
+ }
25
+
26
+ getUrl(): string {
27
+ return `${this.req.protocol}://${this.req.hostname}${this.req.url}`;
28
+ }
29
+
30
+ getAcceptHeader(): string {
31
+ return this.req.headers.accept ?? "";
32
+ }
33
+
34
+ getUserAgent(): string {
35
+ return this.req.headers["user-agent"] ?? "";
36
+ }
37
+
38
+ getQueryParams(): Record<string, string | string[]> {
39
+ const url = new URL(this.getUrl());
40
+ const params: Record<string, string | string[]> = {};
41
+ url.searchParams.forEach((value, key) => {
42
+ const existing = params[key];
43
+ if (existing) {
44
+ params[key] = Array.isArray(existing)
45
+ ? [...existing, value]
46
+ : [existing, value];
47
+ } else {
48
+ params[key] = value;
49
+ }
50
+ });
51
+ return params;
52
+ }
53
+
54
+ getQueryParam(name: string): string | string[] | undefined {
55
+ const url = new URL(this.getUrl());
56
+ const values = url.searchParams.getAll(name);
57
+ if (values.length === 0) return undefined;
58
+ if (values.length === 1) return values[0];
59
+ return values;
60
+ }
61
+
62
+ getBody(): unknown {
63
+ return this.req.body;
64
+ }
65
+ }
66
+ ```
@@ -0,0 +1,29 @@
1
+ # Route Config Template
2
+
3
+ ```typescript
4
+ import type { RoutesConfig } from "@x402/core/server";
5
+
6
+ export const SERVER_ADDRESS = process.env.SERVER_STELLAR_ADDRESS!;
7
+ export const FACILITATOR_URL =
8
+ process.env.FACILITATOR_URL ||
9
+ "https://channels.openzeppelin.com/x402/testnet";
10
+ export const FACILITATOR_API_KEY = process.env.FACILITATOR_API_KEY!;
11
+
12
+ export const PRICE = "$0.001";
13
+ export const NETWORK = "stellar:testnet";
14
+
15
+ export const routesConfig: RoutesConfig = {
16
+ // "GET /api/example": {
17
+ // accepts: [
18
+ // {
19
+ // scheme: "exact",
20
+ // price: PRICE,
21
+ // network: NETWORK,
22
+ // payTo: SERVER_ADDRESS,
23
+ // },
24
+ // ],
25
+ // description: "Example protected endpoint",
26
+ // mimeType: "application/json",
27
+ // },
28
+ };
29
+ ```
@@ -0,0 +1,90 @@
1
+ # Fastify Server Template
2
+
3
+ Uses `@x402/core` directly because `@x402/fastify` is not published on npm.
4
+ Implements a custom Fastify plugin with the `FastifyAdapter` class.
5
+
6
+ ```typescript
7
+ import {
8
+ HTTPFacilitatorClient,
9
+ x402ResourceServer,
10
+ x402HTTPResourceServer,
11
+ } from "@x402/core/server";
12
+ import { ExactStellarScheme } from "@x402/stellar/exact/server";
13
+ import { FastifyAdapter } from "./adapter";
14
+ import {
15
+ routesConfig,
16
+ FACILITATOR_URL,
17
+ FACILITATOR_API_KEY,
18
+ NETWORK,
19
+ } from "./config";
20
+ import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
21
+
22
+ let httpServer: x402HTTPResourceServer | null = null;
23
+ let initPromise: Promise<void> | null = null;
24
+
25
+ function getHTTPServer(): x402HTTPResourceServer {
26
+ if (!httpServer) {
27
+ const facilitatorClient = new HTTPFacilitatorClient({
28
+ url: FACILITATOR_URL,
29
+ createAuthHeaders: async () => {
30
+ const headers = { Authorization: `Bearer ${FACILITATOR_API_KEY}` };
31
+ return { verify: headers, settle: headers, supported: headers };
32
+ },
33
+ });
34
+ const resourceServer = new x402ResourceServer(facilitatorClient).register(
35
+ NETWORK,
36
+ new ExactStellarScheme()
37
+ );
38
+ httpServer = new x402HTTPResourceServer(resourceServer, routesConfig);
39
+ }
40
+ return httpServer;
41
+ }
42
+
43
+ async function ensureInitialized(): Promise<x402HTTPResourceServer> {
44
+ const server = getHTTPServer();
45
+ if (!initPromise) {
46
+ initPromise = server.initialize().catch((err) => {
47
+ initPromise = null;
48
+ throw err;
49
+ });
50
+ }
51
+ await initPromise;
52
+ return server;
53
+ }
54
+
55
+ export async function x402PaymentPlugin(fastify: FastifyInstance) {
56
+ fastify.addHook(
57
+ "onRequest",
58
+ async (req: FastifyRequest, reply: FastifyReply) => {
59
+ const server = await ensureInitialized();
60
+ const adapter = new FastifyAdapter(req);
61
+ const context = {
62
+ adapter,
63
+ path: adapter.getPath(),
64
+ method: adapter.getMethod(),
65
+ paymentHeader:
66
+ adapter.getHeader("x-payment") ??
67
+ adapter.getHeader("x-payment-signature"),
68
+ };
69
+ const result = await server.processHTTPRequest(context);
70
+
71
+ if (result.type === "payment-error") {
72
+ const { status, headers, body, isHtml } = result.response;
73
+ const responseBody = isHtml
74
+ ? (body as string)
75
+ : JSON.stringify(body ?? {});
76
+ const contentType = isHtml ? "text/html" : "application/json";
77
+ reply
78
+ .status(status)
79
+ .headers({ ...headers, "Content-Type": contentType })
80
+ .send(responseBody);
81
+ return reply;
82
+ }
83
+
84
+ if (result.type === "payment-verified") {
85
+ (req as any).__x402Result = result;
86
+ }
87
+ }
88
+ );
89
+ }
90
+ ```