# 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.