Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions tasks/x402-payment-middleware-epic.md
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
Copy link

Copilot AI Jan 10, 2026

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.

Suggested change
- Given a request without valid payment proof, should respond with HTTP 402 and `PAYMENT-REQUIRED` header containing base64-encoded payment requirements
- Given a request without valid payment proof, should respond with HTTP 402 and `PAYMENT-REQUIRED` header containing a base64-encoded payment requirements object with `recipient`, `amount`, `currency`, `network`, `facilitator`, `description`, and `resource` fields (see **402 Response Format**)

Copilot uses AI. Check for mistakes.
- Given a request with valid payment proof in `PAYMENT-SIGNATURE` header, should verify payment via configured facilitator
- 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
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirement states that payment receipt should be attached to response.locals.payment, but in Express.js middleware, request/response context data is typically stored in req.locals or more commonly res.locals. However, the context typically flows through the request object. Consider clarifying whether this should be req.locals.payment or confirm the use of response.locals.payment is intentional for this framework.

Copilot uses AI. Check for mistakes.
- Given failed payment verification, should respond with HTTP 402 and appropriate error details
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirement specifies that failed payment verification should return a 402 response with "appropriate error details", but doesn't specify the format or structure of these error details. For consistency with the rest of the x402 protocol, there should be a standardized error response format specification, similar to how the success case has the PAYMENT-REQUIRED header format defined.

Copilot uses AI. Check for mistakes.
- 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
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirement states that paymentNetwork should default to "Base network for lowest fees," but this hardcodes a specific blockchain network assumption that may not remain accurate over time. Network fees change, and Base may not always have the lowest fees. Consider either: (1) removing the justification "for lowest fees" and just stating "should default to Base network", or (2) making this configurable/updatable, or (3) documenting that this default should be reviewed periodically.

Suggested change
- Given `paymentNetwork` not configured anywhere, should default to Base network for lowest fees
- Given `paymentNetwork` not configured anywhere, should default to Base network

Copilot uses AI. Check for mistakes.
- Given `amount` parameter, should require explicit value (price in smallest unit) with no env fallback
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
- Given `currency` parameter not provided, should default to 'USDC'
- Given response.locals.payment, should include `payer`, `amount`, `currency`, `network`, `transactionHash`, and `timestamp`
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.

---

## Payment Verification

Middleware must verify payment proofs through a facilitator service.

**Requirements**:
- Given a payment proof, should validate signature and payment details against facilitator API
- Given facilitator verification success, should cache proof to avoid re-verification on retries
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
- Given facilitator verification failure, should return 402 with clear error message (insufficient funds, expired, invalid signature)
- Given facilitator unavailability, should return 503 Service Unavailable with retry-after header
Copy link

Copilot AI Jan 10, 2026

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).

Suggested change
- Given facilitator unavailability, should return 503 Service Unavailable with retry-after header
- Given facilitator unavailability, should return 503 Service Unavailable with `Retry-After` header

Copilot uses AI. Check for mistakes.
- Given payment verification, should complete within 5 seconds under normal network conditions
- Given sensitive payment data, should sanitize wallet addresses and transaction hashes in error logs (show first/last 4 chars only)
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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

Copilot uses AI. Check for mistakes.

---

## 402 Response Format

Standardized payment required response following x402 protocol specification.

**Requirements**:
- Given 402 response, should include `PAYMENT-REQUIRED` header with base64-encoded payment requirements
- Given payment requirements, should specify `recipient`, `amount`, `currency`, `network`, and `facilitator` URL
- Given payment requirements, should include `description` field for human-readable payment context
- Given payment requirements, should include `resource` field identifying the requested endpoint
- Given multiple supported networks, should list all in order of preference (lowest fees first)

---

## Test Utilities

Enable testing payment middleware without real blockchain transactions.

**Requirements**:
- Given test environment, should support `createMockFacilitator` that returns configurable verification results
- Given mock facilitator, should simulate success, insufficient funds, expired payment, and network errors
Copy link

Copilot AI Jan 11, 2026

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 uses AI. Check for mistakes.
- Given test setup, should provide `createPaymentProof` helper to generate valid test proofs
- Given createServer test utility, should extend to support payment header injection
Copy link

Copilot AI Jan 10, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
- Given Playwright e2e tests, should verify full payment flow from 402 response through successful payment to resource access
- Given Playwright e2e tests, should verify client receives correct `PAYMENT-REQUIRED` header format on unpaid requests
- Given Playwright e2e tests, should verify client can parse payment requirements and submit valid `PAYMENT-SIGNATURE`

---

## Configuration Integration

Integrate with existing withConfig middleware for payment settings.

**Requirements**:
- Given environment variables, should support `X402_RECIPIENT`, `X402_FACILITATOR`, `X402_PAYMENT_NETWORK` configuration
- Given `recipient` not provided as parameter and `X402_RECIPIENT` not set, should throw descriptive ConfigurationError at middleware creation time
- 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
Comment on lines +93 to +94
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.

---

## Documentation

Update server framework documentation with payment middleware usage.

**Requirements**:
- Given docs/server/README.md, should add createWithPayment to API Reference section
- Given documentation, should include complete example with React/fetch client-side payment flow
- Given documentation, should explain facilitator concept and supported networks
- Given security section, should document payment-specific best practices (recipient validation, amount verification)

---

## Export Updates

Add payment middleware to server exports.

**Requirements**:
- Given src/server/middleware/index.js, should export `createWithPayment`
- Given src/server/middleware/index.js, should export `createMockFacilitator` for testing
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
- Given package.json, should add `@x402/core` as peer dependency
Copy link

Copilot AI Jan 10, 2026

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).

Suggested change
- Given package.json, should add `@x402/core` as peer dependency
- Given package.json, should add `@x402/core@^1.0.0` as peer dependency

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 11, 2026

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.

Suggested change
- 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`

Copilot uses AI. Check for mistakes.

---

## References

- [x402 Protocol Specification](https://www.x402.org/)
- [x402 GitHub Repository](https://github.com/coinbase/x402)
- [Coinbase x402 Developer Docs](https://docs.cdp.coinbase.com/x402/welcome)
- [x402 Whitepaper](https://www.x402.org/x402-whitepaper.pdf)