Summary
Change chunk GET request payment handling to use a fixed-price per-request model that bypasses rate limiting, rather than the current model which adds paid tokens to rate limiter buckets. This maintains the free tier rate limiting while providing a simpler, more predictable paid access model for chunk endpoints.
Current Behavior
When x402 payments are enabled for chunk GET requests (/chunk/:offset):
- Rate limiter uses
CHUNK_GET_BASE64_SIZE_BYTES (default: ~360 KiB) to predict token consumption
- When rate limit exceeded, gateway returns 402 Payment Required
- Client makes payment and includes payment header in retry request
- Payment is verified and settled
- Paid tokens are added to the client's IP bucket (with
X_402_RATE_LIMIT_CAPACITY_MULTIPLIER, default 10x)
- These tokens are consumed for current and future requests
- Tokens are adjusted post-response based on actual size
Code reference: src/routes/chunk/handlers.ts:68-126
Proposed Behavior
Introduce a new fixed-price payment bypass model for chunks:
- Rate limiter continues to enforce free tier limits (unchanged)
- Client can proactively include payment header OR receive 402 when rate limited
- If valid payment header present:
- Skip rate limit checks entirely (neither consume nor add tokens)
- Charge fixed price per chunk request (new config:
CHUNK_PAYMENT_FIXED_PRICE_USDC)
- Verify and settle payment as normal
- Serve chunk data
- If no payment header:
- Apply normal rate limiting using
CHUNK_GET_BASE64_SIZE_BYTES for token calculation
- Return 429/402 when limits exceeded
Rationale
Why this change?
- Simpler mental model: Users pay fixed price per chunk vs. accumulating bucket credits
- Predictable costs: Every chunk request costs exactly the same amount
- No token accounting complexity: Eliminates prediction → adjustment → bucket credit flow
- Better for high-frequency chunk access: Users who need many chunks can pay per-request without managing bucket state
- Preserves free tier: Rate limiting still protects against abuse for unpaid access
- Aligns with chunk characteristics: Chunks have relatively uniform size, making fixed pricing natural
Why not the current model for chunks?
- Chunks are infrastructure primitives, not user content
- Bucket credit model adds complexity when users just want "pay to access this chunk"
- Size variance is lower than general data endpoints, so fixed pricing is fairer
- Per-request payment is simpler for automated/programmatic access patterns
Technical Implementation Approach
1. New Configuration Variables
# Separate chunk payment pricing from rate limiter sizing
CHUNK_PAYMENT_FIXED_PRICE_USDC=0.001 # Fixed price per chunk request
CHUNK_PAYMENT_BYPASS_RATE_LIMIT=true # Payment bypasses rate limits (default true)
# Existing variable - still used for rate limiter token calculation only
CHUNK_GET_BASE64_SIZE_BYTES=368640 # For free tier rate limiting
2. Payment Processing Flow
GET /chunk/:offset with X-Payment header
↓
Check if CHUNK_PAYMENT_BYPASS_RATE_LIMIT enabled
↓
Verify payment (fixed amount, not size-based)
↓
Settle payment immediately
↓
Skip rate limiter entirely
↓
Fetch and serve chunk
↓
NO token adjustment, NO bucket credits
3. Code Changes Required
A. New payment processor method (or parameter):
// New method or flag for fixed-price non-bucket payment
interface PaymentProcessor {
// Existing
verifyAndSettlePayment(...): Promise<PaymentResult>;
// New - fixed price, no bucket integration
verifyAndSettleFixedPricePayment(
fixedPriceUSDC: number,
...
): Promise<PaymentResult>;
}
B. Update chunk handler (src/routes/chunk/handlers.ts):
// Before rate limit check
if (paymentProcessor && CHUNK_PAYMENT_BYPASS_RATE_LIMIT) {
const paymentHeader = extractPaymentHeader(request);
if (paymentHeader) {
// Verify and settle at fixed price
const paymentResult = await paymentProcessor.verifyAndSettleFixedPricePayment(
CHUNK_PAYMENT_FIXED_PRICE_USDC,
paymentHeader,
request,
response
);
if (paymentResult.verified && paymentResult.settled) {
// Skip rate limiter entirely - proceed to fetch chunk
// NO token consumption, NO bucket credits
} else {
// Payment failed - return 402
return;
}
}
}
// If no payment or bypass disabled, proceed with normal rate limiting
if (rateLimiter !== undefined) {
// Existing rate limit logic for free tier
}
C. Update payment response generation:
- When returning 402 for chunks, include fixed price in payment requirement
- Don't calculate based on
perBytePrice, use fixed CHUNK_PAYMENT_FIXED_PRICE_USDC
D. Documentation updates:
- Update
docs/x402-and-rate-limiting.md to explain dual model
- Update
docs/envs.md with new config variables
- Add examples showing chunk-specific payment patterns
4. Backward Compatibility
Option A: Feature flag (recommended for initial rollout)
# Default to false initially, operators opt-in
CHUNK_PAYMENT_FIXED_PRICE_ENABLED=false
Option B: Automatic detection
# If CHUNK_PAYMENT_FIXED_PRICE_USDC is set, use fixed-price model
# Otherwise, use existing token-bucket model
Open Questions
-
Should HEAD requests also support fixed-price payment bypass?
- Current: HEAD uses 0 bytes for rate limiting
- Proposal: HEAD requests are free (no payment), but also respect rate limits
-
Should we expose payment bypass availability in /ar-io/info?
{
"x402": {
"dataEgress": { /* existing */ },
"chunkRequests": {
"fixedPriceEnabled": true,
"fixedPriceUSDC": "0.001000",
"bypassesRateLimits": true
}
}
}
-
Metrics: How to track fixed-price chunk payments separately?
- New metric:
x402_chunk_fixed_price_payments_total
- Distinguish from bucket-credit payments in existing metrics
-
Should POST /chunk remain unmetered?
- Current: Not rate limited
- Keep as-is since it's for data ingestion, not egress
Testing Considerations
- Unit tests: Payment verification without rate limiter integration
- Integration tests:
- Payment bypasses rate limits
- No tokens added to buckets
- Fixed price regardless of response size
- E2E tests:
- Free tier: rate limited as normal
- Paid tier: unlimited access with per-request payment
- Mixed: some requests paid, some free
Related Code References
- Chunk handler:
src/routes/chunk/handlers.ts:68-126
- Rate limiter integration:
src/handlers/data-handler-utils.ts:76-408
- Chunk endpoint documentation:
docs/x402-and-rate-limiting.md:76-91
- Configuration:
src/config.ts:441-443
Priority & Scope
Priority: Medium - enhances but doesn't fix broken functionality
Scope:
- New payment flow for chunks (no bucket integration)
- Configuration additions
- Documentation updates
- Metrics updates
Out of scope (defer to future work):
- Applying fixed-price model to other endpoints
- Retroactive bucket credit refunds
- Payment plan/subscription models
Summary
Change chunk GET request payment handling to use a fixed-price per-request model that bypasses rate limiting, rather than the current model which adds paid tokens to rate limiter buckets. This maintains the free tier rate limiting while providing a simpler, more predictable paid access model for chunk endpoints.
Current Behavior
When x402 payments are enabled for chunk GET requests (
/chunk/:offset):CHUNK_GET_BASE64_SIZE_BYTES(default: ~360 KiB) to predict token consumptionX_402_RATE_LIMIT_CAPACITY_MULTIPLIER, default 10x)Code reference:
src/routes/chunk/handlers.ts:68-126Proposed Behavior
Introduce a new fixed-price payment bypass model for chunks:
CHUNK_PAYMENT_FIXED_PRICE_USDC)CHUNK_GET_BASE64_SIZE_BYTESfor token calculationRationale
Why this change?
Why not the current model for chunks?
Technical Implementation Approach
1. New Configuration Variables
2. Payment Processing Flow
3. Code Changes Required
A. New payment processor method (or parameter):
B. Update chunk handler (
src/routes/chunk/handlers.ts):C. Update payment response generation:
perBytePrice, use fixedCHUNK_PAYMENT_FIXED_PRICE_USDCD. Documentation updates:
docs/x402-and-rate-limiting.mdto explain dual modeldocs/envs.mdwith new config variables4. Backward Compatibility
Option A: Feature flag (recommended for initial rollout)
# Default to false initially, operators opt-in CHUNK_PAYMENT_FIXED_PRICE_ENABLED=falseOption B: Automatic detection
Open Questions
Should HEAD requests also support fixed-price payment bypass?
Should we expose payment bypass availability in
/ar-io/info?{ "x402": { "dataEgress": { /* existing */ }, "chunkRequests": { "fixedPriceEnabled": true, "fixedPriceUSDC": "0.001000", "bypassesRateLimits": true } } }Metrics: How to track fixed-price chunk payments separately?
x402_chunk_fixed_price_payments_totalShould POST /chunk remain unmetered?
Testing Considerations
Related Code References
src/routes/chunk/handlers.ts:68-126src/handlers/data-handler-utils.ts:76-408docs/x402-and-rate-limiting.md:76-91src/config.ts:441-443Priority & Scope
Priority: Medium - enhances but doesn't fix broken functionality
Scope:
Out of scope (defer to future work):