- Added 17 missing endpoints to OpenAPI documentation: * 4 analytics endpoints (status-distribution, networks, metadata-quality) * 2 system endpoints (stats/timeline) * 1 review endpoint (reviews/recent) * 4 mint discovery endpoints (activity, recent, updated, popular) * 6 mint detail endpoints (stats, card, latency/timeseries, availability, trust/history, trust/compare, reviews/summary, views/timeseries) - Fixed duplicate mints bug in recommendation endpoints: * Modified SQL queries to use subquery for uptime_rollups * Prevents cartesian product from 493 duplicate rollup entries * All recommendation endpoints now return unique mints - Affected endpoints: * GET /mints/recommended (all use cases) * GET /wallets/:wallet_name/recommended-mints All 82 API endpoints now documented and tested. All 23 core endpoints verified working.
🌿 Cashumints.space API
A production-ready, decentralized observability, discovery, and reputation API for the Cashu mint ecosystem.
Features
- Mint Discovery - Track and index Cashu mints across the ecosystem
- Uptime Monitoring - Continuous probing with full historical data
- Metadata Tracking - NUT-06 compliant metadata with version history
- Nostr Reviews - NIP-87 based review ingestion from configurable relays
- Trust Scores - Transparent, explainable reputation scoring (0-100)
- Analytics - Pageviews, trending mints, and popularity metrics
- Admin API - Full mint curation and system management
- OpenAPI Docs - Interactive Swagger UI documentation
Quick Start
# Clone and install
git clone <repo>
cd cashumints-api
npm install
# Configure
cp env.example .env
openssl rand -hex 32 # Generate admin key, add to .env
# Initialize database
npm run migrate
# Start API server
npm start
# View documentation
open http://localhost:3000/docs
Production Deployment
Prerequisites
- Node.js 18+
- Nginx (reverse proxy)
- systemd (process management)
- Let's Encrypt (SSL)
Installation
# Create user
sudo useradd -r -s /bin/false cashumints
# Clone to /opt
sudo git clone <repo> /opt/cashumints-api
cd /opt/cashumints-api
# Install dependencies
sudo npm install --production
# Configure
sudo cp env.example .env
sudo openssl rand -hex 32 # Add to .env as ADMIN_API_KEY
sudo nano .env
# Create data directory
sudo mkdir -p data
sudo chown cashumints:cashumints data
# Initialize database
sudo -u cashumints npm run migrate
Systemd Services
# Install service files
sudo cp deploy/cashumints-api.service /etc/systemd/system/
sudo cp deploy/cashumints-workers.service /etc/systemd/system/
# Reload and enable
sudo systemctl daemon-reload
sudo systemctl enable cashumints-api cashumints-workers
# Start services
sudo systemctl start cashumints-api
sudo systemctl start cashumints-workers
# Check status
sudo systemctl status cashumints-api
sudo systemctl status cashumints-workers
# View logs
sudo journalctl -u cashumints-api -f
sudo journalctl -u cashumints-workers -f
Nginx Setup
# Install nginx config
sudo cp deploy/nginx.conf /etc/nginx/sites-available/cashumints-api
sudo ln -s /etc/nginx/sites-available/cashumints-api /etc/nginx/sites-enabled/
# Get SSL certificate
sudo certbot --nginx -d api.cashumints.space
# Test and reload
sudo nginx -t
sudo systemctl reload nginx
API Documentation
Interactive API documentation is available at:
- Swagger UI:
http://localhost:3000/docs - OpenAPI JSON:
http://localhost:3000/openapi.json
API Endpoints
System
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Health check |
| GET | /stats |
System statistics |
| GET | /reviews |
Global reviews feed (filterable) |
| GET | /analytics/uptime |
Ecosystem uptime analytics |
| GET | /analytics/versions |
Mint version distribution |
| GET | /analytics/nuts |
NUT support analytics |
Admin (requires X-Admin-Api-Key header)
| Method | Endpoint | Description |
|---|---|---|
| POST | /admin/mints |
Manually add a mint |
| POST | /admin/mints/{id}/urls |
Add URL to mint |
| POST | /admin/mints/merge |
Merge two mints |
| POST | /admin/mints/split |
Undo a merge |
| POST | /admin/mints/{id}/disable |
Hide from listings |
| POST | /admin/mints/{id}/enable |
Re-enable mint |
| POST | /admin/mints/{id}/metadata/refresh |
Force metadata fetch |
| POST | /admin/mints/{id}/trust/recompute |
Force trust recalc |
| POST | /admin/mints/{id}/status/reset |
Reset stuck state |
| POST | /admin/mints/{id}/probe |
Force immediate probe |
| GET | /admin/mints/{id}/visibility |
Get visibility status |
| GET | /admin/jobs |
View job queue |
| GET | /admin/system/metrics |
System health |
| GET | /admin/audit |
Audit log (filter by mint_id) |
Admin endpoints also support /admin/mints/by-url?url= variants for all operations.
Mints
| Method | Endpoint | Description |
|---|---|---|
| GET | /mints |
List all mints (paginated, filterable) |
| GET | /mints/trending |
Get trending mints by popularity |
| GET | /mints/{mint_id} |
Get mint by ID |
| GET | /mints/by-url?url= |
Get mint by URL |
| POST | /mints/submit |
Submit new mint for tracking |
Mint Details
All endpoints support both /{mint_id} and /by-url?url= variants:
| Endpoint | Description |
|---|---|
/urls |
All URLs for mint (clearnet, Tor, mirrors) |
/metadata |
NUT-06 metadata |
/metadata/history |
Metadata change history |
/status |
Lightweight current status |
/uptime?window=24h|7d|30d |
Uptime statistics |
/uptime/timeseries?window=&bucket= |
Timeseries for charting |
/incidents |
Downtime incidents |
/trust |
Trust score with breakdown |
/reviews |
Nostr reviews (NIP-87) |
/views |
Pageview statistics |
/features |
Derived features (NUTs, Bolt11, etc.) |
Configuration
Copy env.example to .env and configure:
# Server
PORT=3000
HOST=0.0.0.0
NODE_ENV=production
# Admin (REQUIRED - generate with: openssl rand -hex 32)
ADMIN_API_KEY=your-secure-key-here
# Database (SQLite)
DATABASE_PATH=./data/cashumints.db
# Probing
PROBE_TIMEOUT_MS=10000
PROBE_INTERVAL_ONLINE_MS=300000 # 5 minutes
PROBE_INTERVAL_OFFLINE_MS=900000 # 15 minutes
CONSECUTIVE_FAILURES_OFFLINE=3
ABANDONED_AFTER_DAYS=30
# Nostr Relays (comma-separated)
NOSTR_RELAYS=wss://relay.damus.io,wss://relay.nostr.band,wss://nos.lol
# Trust Score Weights (out of 100)
TRUST_WEIGHT_UPTIME=40
TRUST_WEIGHT_SPEED=25
TRUST_WEIGHT_REVIEWS=20
TRUST_WEIGHT_IDENTITY=10
TRUST_PENALTY_MAX=15
# Rate Limiting
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=100
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Nginx (Reverse Proxy) │
│ • SSL termination • Rate limiting • Caching │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ HTTP API (Express.js) │
│ • REST endpoints • Swagger UI • Admin API │
│ • CORS enabled • Compression • Helmet security │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ SQLite Database │
│ mints │ mint_urls │ probes │ metadata │ reviews │ scores │
│ incidents │ pageviews │ jobs │ uptime_rollups │ audit_log │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ Background Workers │
│ Probe │ Metadata │ Nostr │ Rollup │ Trust │ Cleanup │
└─────────────────────────────────────────────────────────────┘
Trust Score
Trust scores (0-100) are computed from:
| Component | Max Points | Based On |
|---|---|---|
| Uptime | 40 | 30-day uptime percentage |
| Speed | 25 | Average response time (RTT) |
| Reviews | 20 | Nostr review quantity & rating |
| Identity | 10 | Metadata completeness |
| Penalties | -15 | Offline status, incidents, instability |
Trust Levels:
- Excellent: 85-100
- High: 70-84
- Medium: 50-69
- Low: 25-49
- Unknown: 0-24
Mint Lifecycle
┌─────────────┐
Discovery ───▶ │ unknown │
└──────┬──────┘
│ successful probe
┌──────▼──────┐
│ online │ ◀──────────┐
└──────┬──────┘ │
│ slow response │ recovery
┌──────▼──────┐ │
│ degraded │ ───────────┤
└──────┬──────┘ │
│ consecutive │
│ failures │
┌──────▼──────┐ │
│ offline │ ───────────┘
└──────┬──────┘
│ > 30 days
┌──────▼──────┐
│ abandoned │
└─────────────┘
Nostr Integration (NIP-87)
The API ingests these event kinds from configured relays:
| Kind | Description |
|---|---|
| 38172 | Cashu mint announcements (self-published by mints) |
| 38173 | Fedimint announcements |
| 38000 | Recommendations/reviews (with #k tag referencing 38172) |
Reviews are parsed for:
- Mint URL (from
uordtags, with or without protocol) - Rating 1-5 (from
ratingtag orqualitytag like"1/1"recommend /"0/1"not recommend) - Content (review text)
Admin API
All admin actions are audited. Never deletes raw data.
# Add a mint manually
curl -X POST http://localhost:3000/admin/mints \
-H "X-Admin-Api-Key: $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"mint_url": "https://mint.example.com", "notes": "Trusted operator"}'
# Get system metrics
curl http://localhost:3000/admin/system/metrics \
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
# Force trust recalculation
curl -X POST http://localhost:3000/admin/mints/{mint_id}/trust/recompute \
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
# View audit log
curl http://localhost:3000/admin/audit \
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
Project Structure
cashumints-api/
├── src/
│ ├── index.js # Server entry point
│ ├── config.js # Configuration
│ ├── db/
│ │ ├── connection.js # Database connection
│ │ ├── migrate.js # Migration runner
│ │ ├── schema.sql # Main schema
│ │ └── schema-admin.sql # Admin schema
│ ├── docs/
│ │ └── openapi.js # OpenAPI specification
│ ├── middleware/
│ │ ├── adminAuth.js # Admin authentication
│ │ ├── errorHandler.js # Error handling
│ │ └── rateLimit.js # Rate limiting
│ ├── routes/
│ │ ├── admin.js # Admin endpoints
│ │ ├── mints.js # Mint endpoints
│ │ └── system.js # System endpoints
│ ├── services/
│ │ ├── AdminService.js # Admin operations
│ │ ├── MintService.js # Mint CRUD
│ │ ├── ProbeService.js # HTTP probing
│ │ ├── MetadataService.js # NUT-06 metadata
│ │ ├── UptimeService.js # Uptime rollups
│ │ ├── TrustService.js # Trust scoring
│ │ ├── ReviewService.js # Nostr reviews
│ │ ├── PageviewService.js # Analytics
│ │ └── JobService.js # Background jobs
│ ├── utils/
│ │ ├── url.js # URL normalization
│ │ ├── crypto.js # Hashing
│ │ └── time.js # Time utilities
│ └── workers/
│ ├── index.js # Combined runner
│ ├── probe.js # Mint probing
│ ├── metadata.js # Metadata fetching
│ ├── nostr.js # Nostr ingestion
│ ├── rollup.js # Uptime aggregation
│ └── trust.js # Trust calculation
├── deploy/
│ ├── cashumints-api.service # API systemd service
│ ├── cashumints-workers.service # Workers systemd service
│ └── nginx.conf # Nginx configuration
├── data/ # SQLite database (auto-created)
├── env.example # Configuration template
├── package.json # Dependencies
└── README.md # This file
Development
# Install dependencies
npm install
# Run in development mode (auto-reload)
npm run dev
# Run specific worker
npm run worker:probe
npm run worker:metadata
npm run worker:nostr
npm run worker:rollup
npm run worker:trust
Design Principles
- History is never erased - All raw data is stored and aggregated. Nothing is overwritten.
- Offline ≠ dead - Mints transition through states. Recovery is always possible.
- URL ≠ identity - Mint identity is stable. Multiple URLs can point to the same mint.
- Trust is derived - Every trust signal is computed from stored data with full breakdown.
- Self-hostable - SQLite by default. No Redis or external queues required.
- Admin transparency - Every admin action is audited. No hidden mutations.
License
MIT
Links
Description
Languages
JavaScript
98.7%
Shell
1.3%