free-crypto-news Integration Guide
Add premium tier with x402 paywall to nirholas/free-crypto-news
Overview
The free-crypto-news repository (20⭐) provides a free crypto news API. This guide shows how to add a premium tier using x402 payments, enabling micropayments for premium news sources.
Installation
Integration Steps
1. Create Premium Tier Configuration
// src/premium/tiers.ts
import { createPremiumTier, PricingStrategy } from "@nirholas/x402-ecosystem/premium";
export const newsTiers = createPremiumTier({
free: {
rateLimit: 100,
ratePeriod: "day",
features: [
"basic-news",
"24h-delay",
"top-10-sources",
],
},
basic: {
price: "4.99",
period: "monthly",
rateLimit: 1000,
ratePeriod: "day",
features: [
"basic-news",
"1h-delay",
"all-free-sources",
"email-alerts",
],
},
premium: {
price: "0.001", // $0.001 per news item
period: "per-request",
features: [
"all-news",
"real-time",
"premium-sources",
"sentiment-analysis",
"ai-summaries",
],
},
enterprise: {
price: "99.99",
period: "monthly",
rateLimit: 100000,
ratePeriod: "day",
features: [
"all-features",
"dedicated-support",
"custom-filters",
"webhooks",
"api-priority",
],
},
});
// Pricing strategy for premium tier
export const premiumPricing = PricingStrategy.tiered([
{ maxRequests: 100, price: "0.001" }, // First 100: $0.001 each
{ maxRequests: 1000, price: "0.0005" }, // Next 900: $0.0005 each
{ maxRequests: 10000, price: "0.0001" }, // Beyond: $0.0001 each
]);
2. Create Paywall Middleware
// src/middleware/x402-paywall.ts
import { PaywallBuilder, PricingStrategy } from "@nirholas/x402-ecosystem/premium";
import type { Request, Response, NextFunction } from "express";
// Environment configuration
const RECIPIENT_ADDRESS = process.env.NEWS_PAYMENT_ADDRESS as `0x${string}`;
/**
* x402 Paywall middleware for premium endpoints
*/
export function createNewsPaywall() {
const paywall = new PaywallBuilder()
.forEndpoint("/api/v1/premium/*")
.withPrice("0.001")
.withToken("USDC")
.withRecipient(RECIPIENT_ADDRESS)
.withDescription("Premium crypto news - real-time access")
.withRateLimit(10000, "day")
.build();
return (req: Request, res: Response, next: NextFunction) => {
// Check for x402 payment header
const paymentHeader = req.headers["x-402-payment"];
if (!paymentHeader) {
// Return 402 Payment Required with payment details
return res.status(402).json({
error: "Payment Required",
message: "This endpoint requires x402 payment",
paymentDetails: {
amount: paywall.price,
token: paywall.token,
recipient: paywall.recipient,
network: "eip155:8453", // Base
facilitator: "https://x402.org/facilitator",
},
x402: {
version: "1.0",
paymentRequired: true,
},
});
}
// Verify payment (simplified - real implementation uses facilitator)
// In production, verify with x402 facilitator service
next();
};
}
/**
* Tiered pricing based on request count
*/
export function createTieredPaywall() {
const pricing = PricingStrategy.tiered([
{ maxRequests: 100, price: "0.001" },
{ maxRequests: 1000, price: "0.0005" },
{ maxRequests: 10000, price: "0.0001" },
]);
return (req: Request, res: Response, next: NextFunction) => {
const userId = req.headers["x-user-id"] as string;
const requestCount = getUserRequestCount(userId);
const price = pricing({
userId,
requestCount,
endpoint: req.path,
});
// Set price for this request
req.x402Price = price;
next();
};
}
function getUserRequestCount(userId: string): number {
// Implement request counting
return 0;
}
declare global {
namespace Express {
interface Request {
x402Price?: string;
}
}
}
3. Create Premium News Endpoints
// src/routes/premium.ts
import { Router } from "express";
import { createNewsPaywall, createTieredPaywall } from "../middleware/x402-paywall.js";
import { fetchPremiumNews, generateAISummary } from "../services/news.js";
const router = Router();
// Apply paywall to all premium routes
router.use(createNewsPaywall());
/**
* GET /api/v1/premium/news
* Real-time premium news feed
*/
router.get("/news", async (req, res) => {
const { topic, limit = 20, sources } = req.query;
const news = await fetchPremiumNews({
topic: topic as string,
limit: parseInt(limit as string),
sources: sources ? (sources as string).split(",") : undefined,
includePaywalled: true, // Include news from premium sources
});
res.json({
success: true,
count: news.length,
data: news,
tier: "premium",
cost: req.x402Price ?? "0.001",
});
});
/**
* GET /api/v1/premium/news/:id/summary
* AI-generated summary of news article
*/
router.get("/news/:id/summary", async (req, res) => {
const { id } = req.params;
const summary = await generateAISummary(id);
res.json({
success: true,
data: {
id,
summary: summary.text,
sentiment: summary.sentiment,
keyPoints: summary.keyPoints,
relatedTopics: summary.relatedTopics,
},
tier: "premium",
cost: "0.002", // AI summary costs more
});
});
/**
* GET /api/v1/premium/sentiment
* Real-time market sentiment analysis
*/
router.get("/sentiment", async (req, res) => {
const { asset, timeframe = "24h" } = req.query;
// Fetch sentiment from premium sources
const sentiment = await fetchSentimentAnalysis(asset as string, timeframe as string);
res.json({
success: true,
data: sentiment,
tier: "premium",
cost: "0.005",
});
});
export default router;
async function fetchSentimentAnalysis(asset: string, timeframe: string) {
// Implement sentiment analysis
return {
asset,
timeframe,
score: 0.65,
trend: "bullish",
sources: 42,
};
}
4. Update Main App
// src/app.ts
import express from "express";
import freeRoutes from "./routes/free.js";
import premiumRoutes from "./routes/premium.js";
import { registerX402Ecosystem } from "@nirholas/x402-ecosystem";
const app = express();
app.use(express.json());
// Free tier routes (existing)
app.use("/api/v1", freeRoutes);
// Premium tier routes (new)
app.use("/api/v1/premium", premiumRoutes);
// Health check with tier info
app.get("/health", (req, res) => {
res.json({
status: "healthy",
tiers: {
free: { available: true, rateLimit: "100/day" },
premium: { available: true, pricing: "pay-per-request" },
},
x402: {
enabled: true,
facilitator: "https://x402.org/facilitator",
},
});
});
export default app;
5. Create Revenue Splitter
Split revenue between content providers:
// src/revenue/splitter.ts
import type { Address } from "@nirholas/x402-ecosystem";
interface RevenueRecipient {
address: Address;
percentage: number;
label: string;
}
/**
* Configure revenue split for news content
*/
export const newsRevenueSplit: RevenueRecipient[] = [
{
address: "0x..." as Address, // Content aggregator
percentage: 40,
label: "content-providers",
},
{
address: "0x..." as Address, // Platform
percentage: 30,
label: "platform",
},
{
address: "0x..." as Address, // Development fund
percentage: 20,
label: "development",
},
{
address: "0x..." as Address, // Community treasury
percentage: 10,
label: "treasury",
},
];
/**
* Calculate payment distribution
*/
export function calculateDistribution(
totalAmount: string,
recipients: RevenueRecipient[]
): Map<Address, string> {
const total = parseFloat(totalAmount);
const distribution = new Map<Address, string>();
for (const recipient of recipients) {
const amount = (total * recipient.percentage / 100).toFixed(6);
distribution.set(recipient.address, amount);
}
return distribution;
}
6. Register with Tool Marketplace
// src/marketplace-registration.ts
import { ToolMarketplace } from "@nirholas/x402-ecosystem";
const marketplace = new ToolMarketplace();
export async function registerNewsService() {
await marketplace.registerTool({
name: "free-crypto-news-premium",
description: "Real-time crypto news with sentiment analysis and AI summaries",
endpoint: "https://news.nirholas.dev/api/v1/premium",
price: "0.001",
category: "Data",
owner: process.env.NEWS_PAYMENT_ADDRESS as `0x${string}`,
metadata: {
rateLimit: "10000/day",
sources: 50,
features: ["real-time", "sentiment", "ai-summaries"],
},
});
console.log("✅ Registered with x402 Tool Marketplace");
}
API Documentation
Premium Endpoints
| Endpoint | Price | Description |
|---|---|---|
GET /api/v1/premium/news |
$0.001 | Real-time news feed |
GET /api/v1/premium/news/:id/summary |
$0.002 | AI summary |
GET /api/v1/premium/sentiment |
$0.005 | Sentiment analysis |
Payment Headers
GET /api/v1/premium/news HTTP/1.1
Host: news.nirholas.dev
X-402-Payment: <payment-token>
X-402-Network: eip155:8453
402 Response
{
"error": "Payment Required",
"paymentDetails": {
"amount": "0.001",
"token": "USDC",
"recipient": "0x...",
"network": "eip155:8453",
"facilitator": "https://x402.org/facilitator"
}
}
Example Client Usage
import { PayableAgent } from "@nirholas/x402-ecosystem";
const agent = new PayableAgent({
privateKey: process.env.X402_PRIVATE_KEY,
maxDailySpend: "1.00",
});
// Fetch premium news
const news = await agent.payForService(
"https://news.nirholas.dev/api/v1/premium/news?topic=ethereum"
);
console.log(`Fetched ${news.count} premium news items`);
console.log(`Cost: $${news.cost}`);
Testing
// test/premium.test.ts
import { describe, it, expect } from "vitest";
import request from "supertest";
import app from "../src/app.js";
describe("Premium News API", () => {
it("should return 402 without payment", async () => {
const res = await request(app)
.get("/api/v1/premium/news")
.expect(402);
expect(res.body.error).toBe("Payment Required");
expect(res.body.paymentDetails.amount).toBe("0.001");
});
it("should return news with valid payment", async () => {
const res = await request(app)
.get("/api/v1/premium/news")
.set("X-402-Payment", "valid-payment-token")
.expect(200);
expect(res.body.success).toBe(true);
expect(res.body.tier).toBe("premium");
});
});
Environment Variables
# Payment recipient address
NEWS_PAYMENT_ADDRESS=0x...
# x402 configuration
X402_FACILITATOR_URL=https://x402.org/facilitator
X402_NETWORK=eip155:8453
# Premium tier settings
PREMIUM_DEFAULT_PRICE=0.001
PREMIUM_RATE_LIMIT=10000
Next Steps
- Clone free-crypto-news repository
- Add @nirholas/x402-ecosystem dependency
- Create premium tier configuration
- Add paywall middleware
- Create premium endpoints
- Register with Tool Marketplace
- Update documentation
Revenue Model
| Tier | Price | Features |
|---|---|---|
| Free | $0 | 100 req/day, 24h delay, basic sources |
| Basic | $4.99/mo | 1000 req/day, 1h delay, all free sources |
| Premium | $0.001/req | Unlimited, real-time, all sources, AI |
| Enterprise | $99.99/mo | 100k req/day, priority, webhooks |