- Remove the General category and GET / endpoint from API docs - Keep the endpoint functional but hidden from Swagger UI - Clean up documentation to focus on core API endpoints
Cashu Redeem API 🪙⚡
A production-grade API for redeeming Cashu tokens (ecash) to Lightning addresses using the cashu-ts library and LNURLp protocol.
🚀 Features
- Decode Cashu tokens - Parse and validate token content
- Redeem to Lightning addresses - Convert ecash to Lightning payments via LNURLp
- Security features - Domain restrictions, rate limiting, input validation
- Robust error handling - Comprehensive error messages
- In-memory caching - Fast mint and wallet instances with connection pooling
- Interactive API Documentation - Complete Swagger/OpenAPI documentation at
/docs
📖 API Documentation
Interactive Swagger Documentation: Visit /docs when running the server for a complete, interactive API reference.
Example: https://cashu-redeem.azzamo.net/docs/
The documentation includes:
- Complete endpoint specifications
- Request/response schemas
- Try-it-out functionality
- Example requests and responses
- Authentication requirements
- Error code documentation
📡 API Endpoints
1. POST /api/decode
Decode a Cashu token and return its content. Supports both v1 and v3 token formats.
Request:
{
"token": "cashuB..."
}
Response:
{
"success": true,
"decoded": {
"mint": "https://mint.azzamo.net",
"totalAmount": 21000,
"numProofs": 3,
"denominations": [1000, 10000, 10000],
"format": "cashuA",
"spent": false
},
"mint_url": "https://mint.azzamo.net"
}
2. POST /api/redeem
Redeem a Cashu token to a Lightning address. Lightning address is optional - if not provided, uses the default address from configuration.
Request:
{
"token": "cashuB...",
"lightningAddress": "user@ln.tips"
}
Request (using default address):
{
"token": "cashuB..."
}
Success Response:
{
"success": true,
"paid": true,
"amount": 21000,
"invoiceAmount": 20580,
"to": "user@ln.tips",
"fee": 1000,
"actualFee": 420,
"netAmount": 20000,
"mint_url": "https://mint.azzamo.net",
"format": "cashuA",
"preimage": "abc123..."
}
Success Response (using default address):
{
"success": true,
"paid": true,
"amount": 21000,
"invoiceAmount": 20580,
"to": "admin@your-domain.com",
"fee": 1000,
"actualFee": 420,
"netAmount": 20000,
"mint_url": "https://mint.azzamo.net",
"format": "cashuA",
"usingDefaultAddress": true,
"message": "Redeemed to default Lightning address: admin@your-domain.com"
}
Payment Verification: The API uses multiple indicators to verify payment success:
paidflag from mint response- Presence of payment preimage
- Payment state indicators
3. POST /api/validate-address
Validate a Lightning address without redemption.
Request:
{
"lightningAddress": "user@ln.tips"
}
Response:
{
"success": true,
"valid": true,
"domain": "ln.tips",
"minSendable": 1,
"maxSendable": 100000000,
"commentAllowed": 144
}
4. GET /api/health
Health check endpoint.
Response:
{
"status": "ok",
"timestamp": "2025-01-14T12:00:00Z",
"uptime": 3600,
"memory": {...},
"version": "1.0.0"
}
🛠 Setup & Installation
Prerequisites
- Node.js >= 18.0.0
- npm or yarn
Installation
- Clone and install dependencies:
git clone <your-repo>
cd cashu-redeem-api
npm install
- Setup environment variables:
cp env.example .env
Edit .env file:
# Server Configuration
PORT=3000
NODE_ENV=development
# API Domain/IP Configuration (for Swagger docs and CORS)
API_DOMAIN=localhost:3000
# Security Configuration
ALLOW_REDEEM_DOMAINS=ln.tips,getalby.com,wallet.mutinywallet.com
API_SECRET=your-secret-key-here
# Default Lightning Address (used when no address is provided in redeem requests)
DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com
# Rate Limiting (requests per minute)
RATE_LIMIT=100
# CORS Configuration
ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com
- Start the server:
# Development
npm run dev
# Production
npm start
Environment Variables
API_DOMAIN Configuration
The API_DOMAIN environment variable is used to configure the correct domain/IP for your API in production. This affects:
- Swagger Documentation: The "Try it out" feature will use the correct server URL
- CORS Configuration: Default CORS origins will use the correct protocol and domain
- API Documentation: Server URLs in the documentation will be accurate
Examples:
# Development
API_DOMAIN=localhost:3000
# Production with domain
API_DOMAIN=api.yourdomain.com
# Production with IP
API_DOMAIN=192.168.1.100:3000
# Production with custom port
API_DOMAIN=yourdomain.com:8080
Note: The protocol (http/https) is automatically determined based on NODE_ENV:
NODE_ENV=development→http://NODE_ENV=production→https://
The API will be available at http://localhost:3000
🔧 Configuration
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
Server port | 3000 |
No |
NODE_ENV |
Environment | development |
No |
ALLOW_REDEEM_DOMAINS |
Comma-separated allowed domains | All allowed | No |
DEFAULT_LIGHTNING_ADDRESS |
Default Lightning address for redemptions | None | No |
RATE_LIMIT |
Requests per minute per IP | 100 |
No |
ALLOWED_ORIGINS |
CORS allowed origins | http://localhost:3000 |
No |
Domain Restrictions
To restrict redemptions to specific Lightning address domains, set:
ALLOW_REDEEM_DOMAINS=ln.tips,getalby.com,wallet.mutinywallet.com
If not set, all domains are allowed.
Default Lightning Address
To set a default Lightning address that will be used when no address is provided in redemption requests:
DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com
This allows users to redeem tokens without specifying a Lightning address - the tokens will automatically be sent to your configured default address. If no default is set, Lightning address becomes required for all redemption requests.
🏗 Architecture
Services
services/cashu.js
- Manages Cashu token parsing and validation
- Handles mint connections and wallet instances
- Performs token melting operations
- Caches mint/wallet connections for performance
services/lightning.js
- Validates Lightning address formats
- Resolves LNURLp endpoints
- Generates Lightning invoices
- Handles domain restrictions
services/redemption.js
- Manages redemption status tracking
- Handles duplicate token detection
Data Flow
- Token Validation - Parse and validate Cashu token structure
- Address Resolution - Resolve Lightning address to LNURLp endpoint
- Invoice Generation - Create Lightning invoice for the amount
- Token Melting - Use cashu-ts to melt token and pay invoice
🔒 Security Features
- Input validation - All inputs are sanitized and validated
- Rate limiting - 100 requests per minute per IP (configurable)
- Domain restrictions - Limit allowed Lightning address domains
- CORS protection - Configurable allowed origins
- Error handling - Comprehensive error messages without data leaks
🚦 Status Codes
| Status | Description |
|---|---|
processing |
Redemption is in progress |
parsing_token |
Validating and parsing the token |
resolving_invoice |
Resolving Lightning address to invoice |
melting_token |
Performing the melt operation |
paid |
Successfully paid and completed |
failed |
Redemption failed (see error details) |
📊 Monitoring
Health Check
curl http://localhost:3000/api/health
Logs
The server logs all requests and errors to console. In production, consider using a proper logging solution like Winston.
🧪 Testing
Interactive Testing with Swagger
The easiest way to test the API is using the interactive Swagger documentation at /docs:
- Visit
http://localhost:3000/docs - Click "Try it out" on any endpoint
- Fill in the request parameters
- Execute the request directly from the browser
Example cURL commands
Decode a token:
curl -X POST http://localhost:3000/api/decode \
-H "Content-Type: application/json" \
-d '{"token":"your-cashu-token-here"}'
Redeem a token to specific address:
curl -X POST http://localhost:3000/api/redeem \
-H "Content-Type: application/json" \
-d '{
"token": "your-cashu-token-here",
"lightningAddress": "user@ln.tips"
}'
Redeem a token to default address:
curl -X POST http://localhost:3000/api/redeem \
-H "Content-Type: application/json" \
-d '{
"token": "your-cashu-token-here"
}'
🚀 Production Deployment
Recommendations
- Use a process manager (PM2, systemd)
- Set up reverse proxy (nginx, Apache)
- Enable HTTPS with SSL certificates
- Use Redis for persistent storage instead of in-memory
- Set up monitoring (Prometheus, Grafana)
- Configure logging (Winston, structured logs)
- Set resource limits and health checks
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
📝 License
MIT License - see LICENSE file for details.