# 🌿 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 ```bash # Clone and install git clone 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 ```bash # Create user sudo useradd -r -s /bin/false cashumints # Clone to /opt sudo git clone /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 ```bash # 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 ```bash # 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: ```bash # 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 `u` or `d` tags, with or without protocol) - Rating 1-5 (from `rating` tag or `quality` tag like `"1/1"` recommend / `"0/1"` not recommend) - Content (review text) ## Admin API All admin actions are audited. Never deletes raw data. ```bash # 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 ```bash # 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 1. **History is never erased** - All raw data is stored and aggregated. Nothing is overwritten. 2. **Offline ≠ dead** - Mints transition through states. Recovery is always possible. 3. **URL ≠ identity** - Mint identity is stable. Multiple URLs can point to the same mint. 4. **Trust is derived** - Every trust signal is computed from stored data with full breakdown. 5. **Self-hostable** - SQLite by default. No Redis or external queues required. 6. **Admin transparency** - Every admin action is audited. No hidden mutations. ## License MIT ## Links - [Cashu Protocol](https://cashu.space) - [Cashu Documentation](https://docs.cashu.space) - [NIP-87 Specification](https://github.com/nostr-protocol/nips/blob/master/87.md) - [Cashu-TS Library](https://cashu-ts.dev)