-
Notifications
You must be signed in to change notification settings - Fork 13
Add payment required middleware for x402 rails #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
00b68ff
831e201
4f87b33
3f070c2
b6f2289
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,126 @@ | ||||||||||||||||||
| # x402 Payment Middleware Epic | ||||||||||||||||||
|
|
||||||||||||||||||
| **Status**: 📋 PLANNED | ||||||||||||||||||
| **Goal**: Enable plug-n-play API monetization via x402 payment protocol middleware | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Overview | ||||||||||||||||||
|
|
||||||||||||||||||
| AI agents and automated systems need to access paid APIs without human intervention, but current payment flows require accounts, sessions, and manual approval. The x402 protocol enables instant, programmatic stablecoin payments embedded directly into HTTP using the long-dormant 402 Payment Required status code. This epic adds payment middleware to the AIDD server framework, allowing developers to monetize APIs with a single middleware addition to their route stack. | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## createWithPayment Factory | ||||||||||||||||||
|
|
||||||||||||||||||
| Factory function that creates middleware requiring payment before granting access to protected resources. | ||||||||||||||||||
|
|
||||||||||||||||||
| ```js | ||||||||||||||||||
| createWithPayment({ | ||||||||||||||||||
| recipient = process.env.X402_RECIPIENT, | ||||||||||||||||||
| facilitatorUrl = process.env.X402_FACILITATOR, | ||||||||||||||||||
| paymentNetwork = process.env.X402_PAYMENT_NETWORK, | ||||||||||||||||||
| amount, | ||||||||||||||||||
| currency = 'USDC', | ||||||||||||||||||
| description, | ||||||||||||||||||
| }) | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| **Requirements**: | ||||||||||||||||||
| - Given a request without valid payment proof, should respond with HTTP 402 and `PAYMENT-REQUIRED` header containing base64-encoded payment requirements | ||||||||||||||||||
| - Given a request with valid payment proof in `PAYMENT-SIGNATURE` header, should verify payment via configured facilitator | ||||||||||||||||||
ericelliott marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
| - Given successful payment verification, should set `PAYMENT-RESPONSE` header with base64-encoded settlement response containing `transactionHash`, `network`, and `settledAt` | ||||||||||||||||||
| - Given successful payment verification, should attach payment receipt to `response.locals.payment` and allow request to proceed | ||||||||||||||||||
|
||||||||||||||||||
| - Given failed payment verification, should respond with HTTP 402 and appropriate error details | ||||||||||||||||||
|
||||||||||||||||||
| - Given named parameters, should accept `{ recipient, facilitatorUrl, paymentNetwork, amount, currency, description }` | ||||||||||||||||||
| - Given `recipient` parameter not provided, should fall back to `process.env.X402_RECIPIENT` via default parameter syntax | ||||||||||||||||||
| - Given `facilitatorUrl` parameter not provided, should fall back to `process.env.X402_FACILITATOR` via default parameter syntax | ||||||||||||||||||
| - Given `paymentNetwork` parameter not provided, should fall back to `process.env.X402_PAYMENT_NETWORK` via default parameter syntax | ||||||||||||||||||
| - Given `paymentNetwork` not configured anywhere, should default to Base network for lowest fees | ||||||||||||||||||
|
||||||||||||||||||
| - Given `paymentNetwork` not configured anywhere, should default to Base network for lowest fees | |
| - Given `paymentNetwork` not configured anywhere, should default to Base network |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The amount parameter is described as "price in smallest unit" but doesn't specify the data type. For financial amounts, especially in blockchain contexts, JavaScript's Number type can lose precision for large values. The requirement should specify whether to use Number, BigInt, or string representation for the amount parameter to prevent precision loss.
| - Given `amount` parameter, should require explicit value (price in smallest unit) with no env fallback | |
| - Given `amount` parameter, should require an explicit string value representing the integer price in smallest unit (e.g., wei) with no env fallback |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an inconsistency in how response.locals.payment is referenced. Line 31 uses response.locals.payment while line 40 uses response.locals.payment in the requirement description. Both should use consistent naming, and it should be clarified whether this refers to the Express response object or a custom abstraction in the AIDD framework.
| - Given response.locals.payment, should include `payer`, `amount`, `currency`, `network`, `transactionHash`, and `timestamp` | |
| - Given `response.locals.payment` on the framework response object, it should include `payer`, `amount`, `currency`, `network`, `transactionHash`, and `timestamp` |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement states that the middleware should cache proofs to avoid re-verification on retries, but doesn't specify cache expiration policy, cache size limits, or cache invalidation strategy. Without these specifications, the cache could grow unbounded or retain stale proofs. Consider adding requirements for cache TTL, maximum cache size, and cache key structure.
| - Given facilitator verification success, should cache proof to avoid re-verification on retries | |
| - Given facilitator verification success, should cache proof to avoid re-verification on retries, subject to TTL, maximum size, and eviction policies | |
| - Given cached proof usage, should only accept proofs that have not exceeded a configurable TTL (default: 10 minutes) to avoid reuse of stale or revoked payments | |
| - Given cache growth beyond a configurable maximum size, should evict entries using a least-recently-used (LRU) or equivalent strategy to prevent unbounded memory usage | |
| - Given payment proof caching, should define cache keys using a combination of proof identifier and contextual fields (e.g., payer, recipient, amount, currency, network, and any nonce/requestId) to prevent incorrect proof reuse across distinct payments |
Copilot
AI
Jan 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header name should be Retry-After (with proper capitalization) following standard HTTP header naming conventions. HTTP header names are case-insensitive but conventionally use title case (e.g., Content-Type, Cache-Control, Retry-After).
| - Given facilitator unavailability, should return 503 Service Unavailable with retry-after header | |
| - Given facilitator unavailability, should return 503 Service Unavailable with `Retry-After` header |
ericelliott marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement to sanitize wallet addresses and transaction hashes by showing only the first/last 4 characters may not provide sufficient information for debugging payment issues. Consider specifying that the full data should be available in secure audit logs while only sanitized versions appear in general application logs.
| - Given sensitive payment data, should sanitize wallet addresses and transaction hashes in error logs (show first/last 4 chars only) | |
| - Given sensitive payment data, should record full wallet addresses and transaction hashes only in secure, access-controlled audit logs, and should sanitize these fields (show first/last 4 chars only) in general application and error logs |
ericelliott marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement mentions that the mock facilitator should simulate "network errors", but doesn't specify other important error scenarios that should be testable, such as signature verification failures, replay attacks, or double-spend attempts. Consider adding these to ensure comprehensive test coverage.
Copilot
AI
Jan 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requirement mentions extending the "createServer test utility" but it's unclear what this utility is or where it exists in the codebase. The requirement should specify the file location (e.g., "Given src/server/test-utils.js") or clarify if this is a new utility that needs to be created as part of this epic. Without this clarification, it's ambiguous whether this refers to an existing utility or needs to be built from scratch.
| - Given createServer test utility, should extend to support payment header injection | |
| - Given `src/server/test-utils/createServer.ts` test utility, should extend it to support payment header injection |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement states that ConfigurationError should be thrown at middleware creation time when required configuration is missing. However, there's no requirement to validate that the facilitator URL is a valid URL format or that it's reachable. Consider adding validation requirements for the facilitatorUrl parameter to catch configuration issues early.
| - Given `facilitatorUrl` not provided as parameter and `X402_FACILITATOR` not set, should throw descriptive ConfigurationError at middleware creation time | |
| - Given production environment, should validate recipient address format before accepting requests | |
| - Given `facilitatorUrl` not provided as parameter and `X402_FACILITATOR` not set, should throw descriptive ConfigurationError at middleware creation time | |
| - Given `facilitatorUrl` provided (via parameter or `X402_FACILITATOR`), should validate that it is a well-formed HTTP(S) URL at middleware creation time and throw a descriptive ConfigurationError if invalid | |
| - Given production environment, should validate recipient address format before accepting requests | |
| - Given production environment, should perform a lightweight facilitator URL reachability or health check at startup (or first use) and fail fast with a clear initialization error if the facilitator cannot be reached |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement to validate recipient address format in production environment only is problematic. Address format validation should occur in all environments to catch configuration errors early during development and testing. Consider validating in all environments but perhaps with different strictness levels.
| - Given production environment, should validate recipient address format before accepting requests | |
| - Should validate recipient address format in all environments before accepting requests (with stricter validation in production if needed) |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement specifies exporting createMockFacilitator from the main middleware index file. Test utilities should typically be exported from a separate test-specific entry point or a dedicated test utilities module, not from the main production middleware exports. This keeps test code separate from production code and reduces bundle size for production users.
| - Given src/server/middleware/index.js, should export `createMockFacilitator` for testing | |
| - Given a dedicated test utilities entry point (e.g. src/server/middleware/test-utils.js), should export `createMockFacilitator` for testing |
Copilot
AI
Jan 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement specifies adding @x402/core as a peer dependency without specifying a version constraint. Best practice for peer dependencies is to specify a version range to ensure compatibility. The requirement should specify the minimum version or version range (e.g., "should add @x402/core@^1.0.0 as peer dependency" or document that the version should match the current x402 specification version).
| - Given package.json, should add `@x402/core` as peer dependency | |
| - Given package.json, should add `@x402/core@^1.0.0` as peer dependency |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement specifies adding @x402/core as a peer dependency. Peer dependencies require users to manually install the package, which may not be the intended behavior for a core payment feature. Consider whether this should be a regular dependency instead, or document why users should manage this dependency themselves. Additionally, specify the required version range for the peer dependency.
| - Given package.json, should add `@x402/core` as peer dependency | |
| - Given package.json, should add `@x402/core` as a dependency with version range `^1.0.0` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement for line 28 specifies "containing base64-encoded payment requirements" but doesn't specify what fields should be in the payment requirements object, creating ambiguity. Line 63 in the "402 Response Format" section provides the detailed specification (recipient, amount, currency, network, facilitator, description, resource). For consistency and clarity, line 28 should either reference the detailed format defined in the "402 Response Format" section or list the required fields inline.