@ronnakamoto/inp-middleware
v1.0.9
Published
INP Protocol middleware for Express.js and Next.js applications - API-driven implementation with automatic metrics integration
Maintainers
Readme
INP Middleware
A TypeScript middleware library for Express.js and Next.js that enables service providers to accept and validate payments using the INP (Internet Native Payments) protocol.
Features
- Unified Middleware: Single middleware function handles both service discovery and payment validation
- Payment Validation: Automatic validation of blockchain payments with support for multiple networks
- Service Discovery: Automatic discovery of service configuration from INP platform
- Type Safety: Full TypeScript support with comprehensive type definitions
- Easy Integration: Simple setup for Express.js and Next.js applications
- Flexible Configuration: Support for custom payment networks, currencies, and validation rules
Installation
npm install @ronnakamoto/inp-middlewareQuick Start
Express.js
import express from 'express';
import { inpMiddleware } from '@ronnakamoto/inp-middleware';
const app = express();
// Apply INP middleware to your API routes
app.use('/api', inpMiddleware({
projectId: 'your-project-id',
logErrors: true
}));
// Your API endpoints - payment validation happens automatically
app.post('/api/payment', (req, res) => {
// Payment is already validated by middleware
// Access payment info: req.inpPayment
// Access service config: req.inpDiscovery
res.json({
success: true,
message: 'Payment processed successfully'
});
});
app.listen(3000);Next.js API Routes
// pages/api/payment.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { inpMiddleware } from '@ronnakamoto/inp-middleware';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
// Your payment processing logic here
res.json({ success: true });
};
export default inpMiddleware({
projectId: 'your-project-id'
})(handler);How It Works
The unified middleware automatically:
- Discovers Service Configuration: Fetches your service's payment requirements from the INP platform
- Validates Payments: Checks payment amount, currency, network, and transaction proof against your service configuration
- Verifies Transactions: Always validates payments on-chain for security
- Enriches Requests: Adds payment and discovery data to the request object
- Handles Errors: Returns appropriate HTTP status codes for payment issues
Payment Information Sources
The middleware can extract payment information from:
- Headers:
X-INP-PaymentorX-Payment - Request Body:
{ payment: { ... } } - Query Parameters:
?payment={...}
Example Payment Object
{
amount: 0.001,
currency: "USDC",
network: "algorand",
walletAddress: "user-wallet-address",
transactionId: "txn_123456789",
proof: "optional-payment-proof"
}Configuration Options
interface INPMiddlewareOptions {
// Required
projectId: string; // Your project ID
// Optional
inpPlatformUrl?: string; // INP platform base URL (defaults to https://internetnativepayment.org)
apiKey?: string; // API key for authentication
timeout?: number; // Request timeout (default: 30000ms)
retries?: number; // Retry attempts (default: 3)
// Payment Validation
validatePayment?: (payment: INPPayment, endpointConfig: any) => Promise<INPValidationResult> | INPValidationResult;
// Error Handling
logErrors?: boolean; // Enable error logging (default: true)
// Metrics Integration
metricsIngestUrl?: string; // Metrics ingest API URL (defaults to inpPlatformUrl/api/metrics/events)
metricsIngestKey?: string; // Bearer token for metrics ingest API authentication
}Metrics Integration
The middleware automatically publishes metrics events for all payment-related activities. This enables real-time monitoring and analytics of your INP-powered services.
Metrics Events
The middleware publishes the following events:
- Payment Required: When a request is made to a paid endpoint without payment
- Payment Validation Failed: When payment validation fails
- Payment Success: When payment is successfully validated
- Free Endpoint: When a request is made to a free endpoint
Event Structure
{
projectId: string;
endpointPath: string;
paid: boolean;
status: 'success' | 'failed';
latencyMs: number;
timestamp: string;
amount?: number;
currency?: string;
walletAddr?: string;
userId?: string;
}Automatic Metrics Publishing
No configuration required! The middleware automatically publishes metrics events using the same authentication and configuration as your INP platform connection.
app.use('/api', inpMiddleware({
projectId: 'your-project-id',
apiKey: 'your-api-key' // Same key used for metrics
}));Metrics Pipeline
The metrics flow works as follows:
- Middleware → Automatically publishes events to INP platform
- INP Platform → Processes events and stores in database
- Dashboard → Displays real-time metrics and analytics
Events are published asynchronously (fire-and-forget) to ensure they don't impact request performance.
Benefits of This Design
- Zero Configuration: No additional environment variables needed
- Secure: Uses existing INP platform authentication
- Simple: Services don't need to know about metrics infrastructure
- Reliable: Leverages existing INP client with retry logic
Service Configuration
Your service configuration is defined in the INP platform and includes:
{
"endpoints": {
"payment": {
"pricing_model": "fixed",
"price": {
"amount": "0.001",
"currency": "USDC"
},
"networks": ["algorand", "ethereum"],
"guaranteed_response_time": "5s"
}
}
}Error Handling
The middleware returns appropriate HTTP status codes:
402 Payment Required: Payment is required but not provided402 Payment Validation Failed: Payment validation failed400 Bad Request: Invalid request or configuration500 Internal Server Error: Unexpected errors
Example Error Response
{
"error": "Payment Required",
"code": "PAYMENT_REQUIRED",
"required": {
"amount": "0.001",
"currency": "USDC",
"networks": ["algorand", "ethereum"]
}
}Advanced Usage
Custom Payment Validation
You can implement custom payment validation logic by providing a validatePayment function:
app.use('/api', inpMiddleware({
projectId: 'your-project-id',
validatePayment: async (payment, endpointConfig) => {
// Your custom validation logic here
if (payment.amount < 0.001) {
return {
isValid: false,
error: 'Payment amount too small'
};
}
// Call your own payment verification service
const verification = await verifyPaymentWithYourService(payment);
if (!verification.success) {
return {
isValid: false,
error: 'Payment verification failed'
};
}
return {
isValid: true,
details: {
transactionVerified: true,
paymentDetails: {
amount: payment.amount,
currency: payment.currency,
network: payment.network,
timestamp: new Date().toISOString()
}
}
};
}
}));The validatePayment function receives:
payment: The payment object from the requestendpointConfig: The endpoint configuration from the INP platform
It should return an INPValidationResult object with isValid boolean and optional error and details properties.
Accessing Payment Data
app.post('/api/service', (req, res) => {
// Payment information
const payment = req.inpPayment;
console.log('Payment amount:', payment?.amount);
console.log('Payment network:', payment?.network);
// Service configuration
const discovery = req.inpDiscovery;
console.log('Service endpoints:', discovery?.endpoints);
// Validation result
const validation = req.inpValidation;
console.log('Payment valid:', validation?.isValid);
res.json({ success: true });
});Direct API Client Usage
import { INPClient } from '@ronnakamoto/inp-middleware';
const client = new INPClient({
// Uses https://internetnativepayment.org by default
apiKey: 'your-api-key'
});
// Discover service configuration
const discovery = await client.getDiscoveryEndpoint({
projectId: 'your-project-id'
});
// Validate payment
const validation = await client.validatePayment({
endpointId: 'endpoint-id',
payment: paymentData
});TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
INPRequest,
INPPayment,
INPDiscoveryEndpoint,
INPValidationResult
} from '@ronnakamoto/inp-middleware';
// Your request handler
function handler(req: INPRequest, res: Response) {
const payment: INPPayment | undefined = req.inpPayment;
const discovery: INPDiscoveryEndpoint | undefined = req.inpDiscovery;
const validation: INPValidationResult | undefined = req.inpValidation;
}Error Handling
import { INPError, INPPaymentError } from '@ronnakamoto/inp-middleware';
app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
if (error instanceof INPPaymentError) {
return res.status(402).json({
error: error.message,
code: error.code,
details: error.details
});
}
if (error instanceof INPError) {
return res.status(error.statusCode).json({
error: error.message,
code: error.code,
details: error.details
});
}
next(error);
});API Reference
Middleware Functions
inpMiddleware(options)
Main middleware function that handles both service discovery and payment validation for Express.js routes.
clearDiscoveryCache(projectId?)
Clears the discovery cache for testing or manual invalidation.
getCachedDiscoveryData(projectId?)
Gets cached discovery data for debugging.
Client Class
INPClient
HTTP client for communicating with the INP platform.
getDiscoveryEndpoint(request): Fetch discovery endpointvalidatePayment(request): Validate paymentinvokeService(request): Invoke service through platformcheckProjectPaymentStatus(projectId): Check if project has payment endpoints
Error Classes
INPError: Base error classINPValidationError: Validation errorsINPPaymentError: Payment-related errorsINPDiscoveryError: Discovery errorsINPClientError: Client errorsINPConfigError: Configuration errors
Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watchDevelopment
# Install dependencies
npm install
# Build the library
npm run build
# Development build with watch
npm run dev
# Lint code
npm run lintContributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
MIT License - see LICENSE file for details.
