Files
Cashu-redeem-api/README.md
Michilis bd18271957 Update README.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 03:50:03 +00:00

321 lines
8.4 KiB
Markdown

# Cashu Redeem API
A production-grade API for redeeming Cashu tokens (ecash) to Lightning addresses using the [cashu-ts](https://github.com/cashubtc/cashu-ts) library and LNURLp protocol.
## Features
- **Decode Cashu tokens** - Parse and validate token content, check spendability at the mint
- **Redeem to Lightning addresses** - Convert ecash to Lightning payments via LNURLp with exact fee calculation
- **Lightning address validation** - Verify addresses and query LNURLp capabilities
- **Duplicate detection** - In-memory tracking prevents double-spend attempts
- **Security** - Domain restrictions, rate limiting, input validation, CORS protection
- **Interactive API docs** - Complete Swagger/OpenAPI documentation at `/docs`
## API Documentation
Interactive Swagger documentation is available at `/docs` when the server is running.
- Local: `http://localhost:3000/docs`
- OpenAPI spec: `http://localhost:3000/openapi.json`
## API Endpoints
### `POST /api/decode`
Decode a Cashu token and return its content. Supports both v3 (`cashuB`) and v1 (`cashuA`) token formats. Checks spendability against the mint.
**Request:**
```json
{
"token": "cashuB..."
}
```
**Response:**
```json
{
"success": true,
"decoded": {
"mint": "https://kashu.me",
"totalAmount": 16,
"numProofs": 5,
"denominations": [8, 4, 2, 1, 1],
"format": "cashuB",
"spent": false
},
"mint_url": "https://kashu.me"
}
```
### `POST /api/redeem`
Redeem a Cashu token to a Lightning address. The Lightning address is optional if a default is configured.
The redemption process:
1. Token validation and parsing
2. Spendability check at the mint
3. Melt quote to determine exact fees
4. Invoice creation for the net amount (token amount minus fees)
5. Token melting and Lightning payment
**Request:**
```json
{
"token": "cashuB...",
"lightningAddress": "user@twentyone.tips"
}
```
**Request (using default address):**
```json
{
"token": "cashuB..."
}
```
**Success Response:**
```json
{
"success": true,
"paid": true,
"amount": 16,
"invoiceAmount": 14,
"to": "user@twentyone.tips",
"fee": 2,
"netAmount": 14,
"mint_url": "https://kashu.me",
"format": "cashuB",
"preimage": "d5af74a3..."
}
```
**Response fields:**
| Field | Description |
|-------|-------------|
| `amount` | Total token amount in sats |
| `invoiceAmount` | Amount sent to the Lightning address (after fees) |
| `fee` | Exact fee charged by the mint (from melt quote) |
| `netAmount` | Net amount received |
| `preimage` | Lightning payment preimage (proof of payment) |
| `usingDefaultAddress` | Present and `true` when the default address was used |
### `POST /api/validate-address`
Validate a Lightning address without performing a redemption. Tests LNURLp resolution and returns address capabilities.
**Request:**
```json
{
"lightningAddress": "user@twentyone.tips"
}
```
**Response:**
```json
{
"success": true,
"valid": true,
"domain": "twentyone.tips",
"minSendable": 1,
"maxSendable": 1000000,
"commentAllowed": 2000
}
```
### `GET /api/health`
Health check endpoint returning server status, uptime, and memory usage.
**Response:**
```json
{
"status": "ok",
"timestamp": "2026-02-17T03:36:40.987Z",
"uptime": 170.23,
"memory": { "rss": 83873792, "heapTotal": 20520960, "heapUsed": 17170824 },
"version": "2.0.0"
}
```
### `GET /openapi.json`
Returns the full OpenAPI 3.0 specification as JSON.
## Setup & Installation
### Prerequisites
- Node.js >= 18.0.0
- npm >= 8.0.0
### Installation
1. **Clone and install dependencies:**
```bash
git clone https://github.com/Michilis/cashu-redeem-api.git
cd cashu-redeem-api
npm install
```
2. **Configure environment variables:**
```bash
cp env.example .env
```
Edit `.env`:
```bash
# 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=*
# Default Lightning Address (used when no address is provided in redeem requests)
DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com
# Rate Limiting (requests per minute per IP)
RATE_LIMIT=30
# Logging
LOG_LEVEL=info
# CORS Configuration
ALLOWED_ORIGINS=*
```
3. **Start the server:**
```bash
# Development (with auto-reload)
npm run dev
# Production
npm start
```
## Configuration
### Environment Variables
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `PORT` | Server port | `3000` | No |
| `NODE_ENV` | Environment (`development` / `production`) | `development` | No |
| `API_DOMAIN` | Domain for Swagger docs and CORS | `localhost:3000` | No |
| `ALLOW_REDEEM_DOMAINS` | Comma-separated allowed Lightning address domains (`*` for all) | All allowed | No |
| `DEFAULT_LIGHTNING_ADDRESS` | Default Lightning address for redemptions | None | No |
| `RATE_LIMIT` | Requests per minute per IP | `100` | No |
| `LOG_LEVEL` | Logging level | `info` | No |
| `ALLOWED_ORIGINS` | CORS allowed origins (`*` for all) | `http://localhost:3000` | No |
### Domain Restrictions
Restrict redemptions to specific Lightning address domains:
```bash
ALLOW_REDEEM_DOMAINS=twentyone.tips,getalby.com,walletofsatoshi.com
```
If set to `*` or not set, all domains are allowed.
### Default Lightning Address
Set a fallback address used when no address is provided in redemption requests:
```bash
DEFAULT_LIGHTNING_ADDRESS=admin@your-domain.com
```
If no default is configured, the `lightningAddress` field becomes required for all redemption requests.
## Project Structure
```
cashu-redeem-api/
server.js # Express app, middleware, route mounting
swagger.config.js # OpenAPI/Swagger configuration and schemas
components/
cashu.js # Token parsing, spendability checks, melt operations
lightning.js # LNURLp resolution, invoice creation, address validation
redemption.js # Orchestrates the full redemption flow
routes/
cashu.js # POST /api/decode
redemption.js # POST /api/redeem
lightning.js # POST /api/validate-address
health.js # GET /api/health
```
## Redemption Flow
1. **Token Parsing** - Validate and decode the Cashu token structure
2. **Spendability Check** - Verify proofs are unspent at the mint
3. **Melt Quote** - Get exact fee from the mint before creating the invoice
4. **Address Resolution** - Resolve Lightning address via LNURLp
5. **Invoice Generation** - Create a Lightning invoice for the net amount (total minus fee)
6. **Token Melting** - Melt the token at the mint to pay the invoice
## Internal Status Codes
| Status | Description |
|--------|-------------|
| `processing` | Redemption initiated |
| `parsing_token` | Validating and parsing the token |
| `checking_spendability` | Checking proofs at the mint |
| `getting_melt_quote` | Requesting fee quote from mint |
| `resolving_invoice` | Creating Lightning invoice via LNURLp |
| `melting_token` | Performing the melt operation |
| `paid` | Successfully completed |
| `failed` | Redemption failed (see error details) |
## Security Features
- **Input validation** - All inputs are sanitized and validated
- **Rate limiting** - Configurable per-IP request limits
- **Domain restrictions** - Limit allowed Lightning address domains
- **CORS protection** - Configurable allowed origins
- **Duplicate detection** - Prevents resubmission of already-redeemed tokens
- **Error handling** - Comprehensive error messages without sensitive data leaks
## Testing
The easiest way to test the API is using the interactive Swagger documentation:
1. Start the server: `npm run dev`
2. Visit `http://localhost:3000/docs`
3. Click "Try it out" on any endpoint
4. Fill in the request parameters and execute
Or use curl:
```bash
# Health check
curl http://localhost:3000/api/health
# Decode a token
curl -X POST http://localhost:3000/api/decode \
-H "Content-Type: application/json" \
-d '{"token": "cashuB..."}'
# Validate a Lightning address
curl -X POST http://localhost:3000/api/validate-address \
-H "Content-Type: application/json" \
-d '{"lightningAddress": "user@twentyone.tips"}'
# Redeem a token
curl -X POST http://localhost:3000/api/redeem \
-H "Content-Type: application/json" \
-d '{"token": "cashuB...", "lightningAddress": "user@twentyone.tips"}'
```
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Submit a pull request
## License
MIT License - see LICENSE file for details.