A privacy-focused API for creating Monero donation links with subaddress generation. Each donation request generates a unique subaddress, improving privacy for both donors and recipients.
- Subaddress Generation: Automatically generates unique Monero subaddresses for each donation
- View Key Encryption: Private view keys are encrypted at rest using AES-256-GCM
- Rate Limiting: Built-in protection against abuse
- Tor Support: Full support for Tor hidden service deployments
- No Tracking: No analytics, no cookies, no logs of sensitive data
- Node.js 22+
- PostgreSQL 16+
- Docker & Docker Compose (for production)
-
Clone the repository:
git clone https://github.com/anonomi-org/paylinks-api.git cd paylinks-api -
Install dependencies:
npm install
-
Start the development database:
docker compose -f docker-compose.dev.yml up -d
-
Copy and configure environment variables:
cp .env.example .env # Edit .env with your values -
Run migrations:
npm run migrate up
-
Start the development server:
npm run dev
-
Configure environment variables:
cp .env.example .env # Edit .env with production values -
Generate required secrets:
# Encryption key for view keys openssl rand -base64 32 # Fingerprint HMAC key openssl rand -hex 32 # Database password openssl rand -hex 16
-
Start the services:
docker compose up -d
-
Run migrations:
docker compose --profile migrate up migrate
To update the deployment:
git pull && docker compose up -d --buildThis is safe - database data persists in the Docker volume.
| Variable | Required | Description |
|---|---|---|
PORT |
No | API port (default: 8787) |
HOST |
No | Bind address (default: 0.0.0.0) |
DATABASE_URL |
Yes | PostgreSQL connection string |
PAYLINKS_MASTER_KEY_B64 |
Yes | Base64-encoded 32-byte AES key for encrypting view keys |
PAYLINKS_FINGERPRINT_KEY |
Yes | HMAC key for paylink fingerprints (min 16 chars) |
ALLOWED_ORIGINS |
Yes | Comma-separated list of allowed CORS origins |
ALLOW_NULL_ORIGIN |
No | Set to true for Tor deployments (see below) |
DONATE_BASE_URL |
Yes | Base URL for donation page (e.g., https://example.org/donate#) |
NODE_ENV |
No | Set to production for strict validation |
For Tor hidden service deployments, set:
ALLOW_NULL_ORIGIN=trueThis is required because Tor Browser sends Origin: null for privacy. This setting returns Access-Control-Allow-Origin: * for null origins, allowing requests from Tor Browser.
Do not enable this on clearnet deployments.
GET /health
POST /api/paylinks
Content-Type: application/json
{
"publicAddress": "4...",
"privateViewKey": "...",
"options": {
"label": "My Donation Link",
"minIndex": 1,
"maxIndex": 100
}
}
GET /api/paylinks/:id/meta
POST /api/paylinks/:id/request
Content-Type: application/json
{
"amount": "0.1",
"description": "Coffee donation"
}
POST /api/paylinks/:id/delete
Content-Type: application/json
{
"ownerKey": "..."
}
POST /api/paylinks/delete
Content-Type: application/json
{
"ownerKey": "..."
}
- Private view keys are encrypted using AES-256-GCM before storage
- Owner keys are derived from public address + private view key (never stored directly)
- Delete operations use constant-time responses to prevent enumeration
- UUID validation prevents timing attacks on paylink IDs
- Rate limiting protects against brute force attacks
GPL-3.0 - See LICENSE for details.