A Node.js/Express API for managing micro-donations on the Stellar blockchain network. Supports one-time donations, recurring donation schedules, wallet management, and donation analytics.
- Features
- Architecture
- Getting Started
- Runtime Configuration
- API Endpoints
- Database Schema
- Development
- Testing
- Troubleshooting
- Documentation
- One-Time Donations: Create and verify donations on Stellar testnet/mainnet
- Recurring Donations: Schedule automated recurring donations (daily, weekly, monthly)
- Wallet Management: Track wallets and query transaction history
- Analytics: Get donation statistics and summaries
- API Key Rotation: Zero-downtime key rotation with versioning and graceful deprecation
- Mock Mode: Development mode with simulated Stellar operations
- Debug Mode: Configurable verbose logging for local development troubleshooting
- Failure Simulation: Comprehensive network failure testing for robust error handling
- Automated Scheduler: Background service for executing recurring donations
- Rate Limiting: Protection against abuse with configurable request limits on donation endpoints
- Idempotency: Prevent duplicate transactions with idempotency key support
- Sensitive Data Masking: Automatic masking of secrets, API keys, and private values in all logs
┌─────────────┐
│ Clients │
│ (Web/Mobile)│
└──────┬──────┘
│ HTTP/HTTPS
▼
┌─────────────────────────────────┐
│ Express.js API Layer │
│ /donations /wallets /stream │
└──────┬──────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ Service Layer │
│ Stellar Service | Scheduler │
└──────┬──────────────────────────┘
│
├──────────────┬────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌─────────┐
│ SQLite │ │ Stellar │ │ Horizon │
│ Database │ │ Network │ │ API │
└──────────┘ └──────────┘ └─────────┘
For detailed architecture documentation, see:
- Full Architecture Documentation - Comprehensive diagrams and component details
- Simple Architecture Diagram - ASCII art overview
- API Layer: Express.js routes handling HTTP requests
- Service Layer: Business logic and Stellar blockchain integration
- Data Layer: SQLite database for persistent storage
- Scheduler: Background service for recurring donations (runs every 60s)
- Node.js (v20 or higher)
- npm or yarn
- SQLite3
- Clone the repository:
git clone https://github.com/yourusername/Stellar-Micro-Donation-API.git
cd Stellar-Micro-Donation-API- Install dependencies:
npm install- Configure environment variables:
cp .env.example .env
# Edit .env — at minimum set ENCRYPTION_KEY (run `npm run generate-key`) and API_KEYS- Initialize the database:
npm run init-db- Start the server:
npm startThe API will be available at http://localhost:3000
For development with auto-reload:
npm run devEnable verbose logging for troubleshooting:
# Add to .env file
DEBUG_MODE=true
# Start server with debug logging
npm startSee Debug Mode Documentation for details.
Get started with the API immediately using:
Option 1: Postman/Insomnia Collection
- Import Stellar-Micro-Donation-API.postman_collection.json into Postman or Insomnia
- Set the
API_KEYvariable with your API key - All core flows are pre-configured (wallet management, donations, recurring donations, statistics, SSE)
Option 2: Curl Commands
- See API_CURL_EXAMPLES.md for copy-paste curl commands
- Covers all core flows with examples and troubleshooting tips
For comprehensive documentation of runtime environment assumptions, timeouts, retry logic, persistence requirements, background services, and operational procedures, see:
RUNTIME_ASSUMPTIONS.md - Complete runtime environment documentation
This document covers:
- Network Configuration: Timeouts, retry logic, external dependencies
- Persistence Layer: Database paths, storage requirements, backup strategies
- Background Services: Scheduler intervals, service behavior, lifecycle management
- Resource Requirements: Memory, disk, CPU, and network requirements by deployment scale
- Configuration Reference: All environment variables with validation rules
- Production Deployment: Warnings, readiness checklist, monitoring recommendations
- Operational Procedures: Graceful shutdown, troubleshooting guide
For detailed request/response examples with error handling, see the Complete API Examples Documentation.
POST /donations- Create a new donationGET /donations- List all donationsGET /donations/recent?limit=10- Get recent donationsGET /donations/:id- Get specific donationGET /donations/limits- Get donation amount limitsPOST /donations/verify- Verify transaction on blockchainPATCH /donations/:id/status- Update donation status
POST /wallets- Create wallet metadataGET /wallets- List all walletsGET /wallets/:id- Get specific walletGET /wallets/:publicKey/transactions- Get all transactions for a walletPATCH /wallets/:id- Update wallet metadata
POST /stream/create- Create recurring donation scheduleGET /stream/schedules- List all schedulesGET /stream/schedules/:id- Get specific scheduleDELETE /stream/schedules/:id- Cancel schedule
GET /stats/daily- Get daily donation statisticsGET /stats/weekly- Get weekly donation statisticsGET /stats/summary- Get summary analyticsGET /stats/donors- Get donor statisticsGET /stats/recipients- Get recipient statisticsGET /stats/analytics-fees- Get analytics fee summaryGET /stats/wallet/:walletAddress/analytics- Get wallet analytics
GET /transactions- Get paginated transactionsPOST /transactions/sync- Sync wallet transactions from Stellar network
GET /health- API health status
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
publicKey TEXT NOT NULL UNIQUE,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
);CREATE TABLE transactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
senderId INTEGER NOT NULL,
receiverId INTEGER NOT NULL,
amount REAL NOT NULL,
memo TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (senderId) REFERENCES users(id),
FOREIGN KEY (receiverId) REFERENCES users(id)
);CREATE TABLE recurring_donations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
donorId INTEGER NOT NULL,
recipientId INTEGER NOT NULL,
amount REAL NOT NULL,
frequency TEXT NOT NULL,
nextExecutionDate DATETIME NOT NULL,
status TEXT DEFAULT 'active',
executionCount INTEGER DEFAULT 0,
FOREIGN KEY (donorId) REFERENCES users(id),
FOREIGN KEY (recipientId) REFERENCES users(id)
);Stellar-Micro-Donation-API/
├── src/
│ ├── config/ # Configuration files
│ ├── middleware/ # Express middleware
│ ├── routes/ # API route handlers
│ │ ├── app.js
│ │ ├── donation.js
│ │ ├── wallet.js
│ │ ├── stream.js
│ │ ├── transaction.js
│ │ └── stats.js
│ ├── services/ # Business logic services
│ │ ├── StellarService.js
│ │ ├── MockStellarService.js
│ │ └── RecurringDonationScheduler.js
│ ├── scripts/ # Database scripts
│ │ └── initDB.js
│ └── utils/ # Utility functions
│ ├── database.js
│ └── permissions.js
├── data/ # SQLite database files
├── docs/ # Documentation
├── tests/ # Test files
└── package.json
The API uses role-based access control (RBAC) with three roles:
| Role | Permissions | Use Case |
|---|---|---|
| admin | All permissions (*) |
System administration, API key management |
| user | donations:, wallets:, stream:, stats:read, transactions: | Standard API operations |
| guest | donations:read, stats:read | Read-only public access |
For detailed permission audit and security hardening, see API Key Permissions Audit.
Create a .env file in the project root:
STELLAR_NETWORK=testnet
HORIZON_URL=https://horizon-testnet.stellar.org
PORT=3000For API key authentication, use the new database-backed system (recommended):
npm run keys:create -- --name "My Key" --role user --expires 365Or use legacy environment-based keys (deprecated):
API_KEYS=your-api-key-hereRequired at startup:
API_KEYS(legacy method, or use database-backed keys)ENCRYPTION_KEY(required only whenNODE_ENV=production)
Validated at startup (if provided):
PORTmust be an integer from 1 to 65535STELLAR_NETWORKmust be one oftestnet,mainnet,futurenetMOCK_STELLARmust betrueorfalseHORIZON_URLmust be a valid URL
The API supports zero-downtime key rotation. See:
- API Key Rotation Guide - Complete documentation
- Quick Start Guide - Common commands
Quick commands:
npm run keys:create -- --name "My Key" --role user --expires 365
npm run keys:list
npm run keys -- deprecate --id 1
npm run keys -- revoke --id 2npm testAll tests are fully isolated and can run independently in any order:
# Run tests in random order to verify isolation
npm test -- --randomize
# Run with specific seed to reproduce order
npm test -- --randomize --seed=123456For detailed information about test isolation, see Test Isolation Guide.
npm run test:coverageThis generates:
- Terminal coverage summary
- HTML report at
coverage/lcov-report/index.html - LCOV report for CI/CD integration
- JSON summary for programmatic access
npm run check-coverageValidates that coverage meets minimum thresholds:
- Branches: 60%
- Functions: 60%
- Lines: 60%
- Statements: 60%
After running coverage, open the HTML report:
# macOS
open coverage/lcov-report/index.html
# Windows
start coverage/lcov-report/index.html
# Linux
xdg-open coverage/lcov-report/index.htmlCoverage is automatically enforced in CI/CD:
- ✅ PRs must meet minimum 60% coverage thresholds
- ❌ Builds fail if coverage drops below thresholds
- 📊 Coverage reports uploaded as artifacts (30-day retention)
For detailed coverage documentation, see Coverage Guide.
npm test -- tests/integration.test.jsComprehensive end-to-end tests for all donation endpoints:
npm test tests/donation-routes-integration.test.jsCoverage: 60+ test cases covering:
- All 7 donation endpoints
- Success and failure scenarios
- Validation, authentication, idempotency
- Rate limiting and error handling
- No live Stellar network required (uses MockStellarService)
For detailed information, see Donation Routes Integration Tests.
node test-recurring-donations.jsThe project includes comprehensive failure simulation for testing network errors and retry logic:
# Run failure simulation tests
npm test tests/stellar-network-failures.test.js
# Run retry logic tests
npm test tests/stellar-retry-logic.test.jsFailure Types Tested:
- Timeouts and network errors
- Service unavailability
- Transaction failures (bad sequence, insufficient fee)
- Rate limiting
- Partial responses
For detailed information, see Stellar Failure Simulation Guide.
Having issues? We've got you covered!
- Server won't start? Check environment:
npm run validate-env - Tests failing? Clear cache:
npx jest --clearCache - Port in use? Kill process:
kill -9 $(lsof -ti:3000) - Dependencies broken? Fresh install:
rm -rf node_modules package-lock.json && npm install
The server refuses to start without an encryption key when NODE_ENV=production.
# Generate a key
npm run generate-key
# Copy the output into .env
ENCRYPTION_KEY=<64-char hex output>If you are running locally, set NODE_ENV=development to skip enforcement, or provide a key regardless (recommended).
API_KEYS is missing or empty. Add at least one key to .env:
API_KEYS=dev_key_1234567890To use the database-backed key system instead (recommended for production):
npm run keys:create -- --name "My Key" --role user --expires 365Run the init script before the first start:
npm run init-dbIf the database exists but is missing new tables introduced by a migration, run:
npm run migrateKill whatever process owns the port:
kill -9 $(lsof -ti:3000)Or change the port in .env:
PORT=3001The following integrations are completely optional. If their env vars are absent the feature is disabled and the API continues working:
| Integration | Required vars | Fallback behaviour |
|---|---|---|
| CoinGecko price oracle | COINGECKO_API_KEY |
Public rate-limited endpoint is used |
| IPFS certificate pinning | PINATA_API_KEY, PINATA_SECRET_KEY |
Certificates stored in local memory only |
| Email receipts (SMTP) | SMTP_HOST, SMTP_USER, SMTP_PASS, SMTP_FROM |
Email delivery skipped/graceful failure |
| Geographic IP blocking | GEO_BLOCKED_COUNTRIES, MAXMIND_DB_PATH |
All IPs allowed; no geo rules applied |
| KMS key wrapping | KMS_KEY_ID, AWS_REGION |
Software-only encryption is used |
| Webhooks (external) | WEBHOOK_SECRET |
Outbound webhooks still fire; no signature |
To confirm which integrations are active at runtime, call GET /health — the response includes dependency status.
cp .env.example .env
# Then edit .env — at minimum set ENCRYPTION_KEY and API_KEYSAvoid needing a real Stellar account during development:
MOCK_STELLAR=true- Full Troubleshooting Guide - Comprehensive solutions
- Quick Reference - Fast fixes for common problems
- Check GitHub Issues for known problems
- Search Discussions for community help
Enable detailed logging for troubleshooting:
DEBUG_MODE=true LOG_VERBOSE=true npm startAll variables are read from the .env file in the project root (see .env.example).
| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | 3000 |
Port the HTTP server listens on (1–65535) |
NODE_ENV |
No | development |
Runtime environment (development | production | test) |
| Variable | Required | Default | Description |
|---|---|---|---|
API_KEYS |
Yes (legacy) | — | Comma-separated list of accepted API keys. Not needed when using database-backed keys exclusively. |
| Variable | Required | Default | Description |
|---|---|---|---|
ENCRYPTION_KEY |
Yes in production | — | 64-character hex string (32 bytes) used to encrypt sensitive data. Generate with npm run generate-key. Changing this makes previously-encrypted data unrecoverable. |
| Variable | Required | Default | Description |
|---|---|---|---|
STELLAR_NETWORK |
No | testnet |
Target network: testnet | mainnet | futurenet |
MOCK_STELLAR |
No | true |
When true, no outbound Stellar calls are made. Recommended for local dev and CI. |
HORIZON_URL |
No | network default | Override the Horizon API endpoint |
| Variable | Required | Default | Description |
|---|---|---|---|
DB_PATH |
No | ./data/stellar_donations.db |
Path to the SQLite file |
DB_POOL_SIZE |
No | 5 |
Number of pooled SQLite connections |
DB_ACQUIRE_TIMEOUT |
No | 10000 |
Milliseconds to wait for a connection before timing out |
| Variable | Required | Default | Description |
|---|---|---|---|
CORS_ALLOWED_ORIGINS |
No | http://localhost:3000,... |
Comma-separated allowed origins for browser clients |
CORS_ALLOWED_METHODS |
No | standard verbs | Override allowed HTTP methods |
CORS_ALLOWED_HEADERS |
No | standard headers | Override allowed request headers |
CORS_MAX_AGE |
No | 86400 |
Preflight cache duration in seconds |
| Variable | Required | Default | Description |
|---|---|---|---|
DEBUG_MODE |
No | false |
Enable verbose debug logging. Never enable in production. |
LOG_TO_FILE |
No | false |
Write logs to files in addition to stdout |
LOG_DIR |
No | ./logs |
Directory for log files (used when LOG_TO_FILE=true) |
LOG_VERBOSE |
No | false |
Include request/response bodies in console output |
| Variable | Required | Default | Description |
|---|---|---|---|
MIN_DONATION_AMOUNT |
No | 0.01 |
Minimum donation amount in XLM |
MAX_DONATION_AMOUNT |
No | 10000 |
Maximum donation amount in XLM |
MAX_DAILY_DONATION_PER_DONOR |
No | 0 (no limit) |
Daily cap per donor in XLM |
| Variable | Required | Default | Description |
|---|---|---|---|
RATE_LIMIT |
No | 100 |
Maximum requests per IP per window |
AUTH_TOKEN_RATE_LIMIT |
No | 10 |
Auth token endpoint requests per minute per IP |
AUTH_REFRESH_RATE_LIMIT |
No | 20 |
Auth refresh endpoint requests per minute per IP |
All variables in this section are optional. Omitting them disables the integration gracefully.
| Variable | Default | Description |
|---|---|---|
COINGECKO_API_KEY |
— | API key for XLM/fiat rates. Without it the public (rate-limited) endpoint is used. |
| Variable | Default | Description |
|---|---|---|
PINATA_API_KEY |
— | Pinata API key for IPFS certificate pinning |
PINATA_SECRET_KEY |
— | Pinata secret key |
IPFS_GATEWAY_URL |
https://gateway.pinata.cloud/ipfs |
Public IPFS gateway base URL |
| Variable | Default | Description |
|---|---|---|
SMTP_HOST |
— | SMTP relay hostname |
SMTP_PORT |
587 |
SMTP port |
SMTP_SECURE |
false |
Use TLS (true) or STARTTLS (false) |
SMTP_USER |
— | SMTP authentication username |
SMTP_PASS |
— | SMTP authentication password |
SMTP_FROM |
— | Sender address (must be verified with your provider) |
| Variable | Default | Description |
|---|---|---|
GEO_BLOCKED_COUNTRIES |
— | Comma-separated ISO country codes to block (e.g. RU,IR,KP) |
GEO_ALLOWED_COUNTRIES |
— | Comma-separated ISO country codes to always allow (overrides blocked list) |
GEO_ALLOWED_IPS |
— | Comma-separated IPs / CIDR ranges that bypass geo-blocking |
MAXMIND_DB_PATH |
./data/GeoLite2-Country.mmdb |
Path to MaxMind GeoLite2 database file |
| Variable | Default | Description |
|---|---|---|
KMS_KEY_ID |
— | AWS KMS key ID or ARN for envelope encryption |
AWS_REGION |
— | AWS region for KMS calls |
| Variable | Default | Description |
|---|---|---|
WEBHOOK_SECRET |
— | HMAC secret used to sign outbound webhook payloads |
SIGNED_URL_EXPIRY_MS |
3600000 (1 hour) |
Expiry for signed export download URLs |
| Variable | Default | Description |
|---|---|---|
SERVICE_SECRET_KEY |
— | Stellar secret key for service-side signing. Never commit a real key. |
The API can work with both Stellar testnet and mainnet. Configure via environment variables:
- Testnet (default): For development and testing
- Mainnet: For production use
The scheduler runs automatically when the server starts and checks for due donations every 60 seconds. It can be configured in src/services/RecurringDonationScheduler.js.
- API Examples - Complete request/response examples for all endpoints
- Quick Start Guide - Getting started quickly
- Troubleshooting Guide - Solutions for common issues
- Quick Reference - Fast fixes for common problems
- Architecture Documentation - Detailed system architecture
- Versioning Strategy - SemVer rules, release flow, and breaking change policy
- Stellar Failure Simulation - Network failure testing guide
- API Flow Diagram - API request flow
- Mock Stellar Guide - Using mock Stellar service
- Kubernetes Probes - Liveness and readiness probe configuration
- Pre-Deployment Checklist - Production deployment verification
- CI Pipeline Documentation - Understanding CI/CD workflows
- Test Coverage Guide - Writing and maintaining tests
Please read our Contributing Guide before submitting a PR.
New to the project? Check out our Onboarding Checklist for a step-by-step guide to getting started!
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests
- Run tests locally (
npm test) - Check coverage (
npm run test:coverage) - Ensure coverage thresholds are met (
npm run check-coverage) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Note: All CI checks must pass before merge, including:
- ✅ All tests passing
- ✅ Coverage thresholds met (60% minimum)
- ✅ Linting checks passed
- ✅ Security checks passed
See Branch Protection and Coverage Guide for details.
This project is licensed under the MIT License.
- Stellar Development Foundation - Blockchain platform
- Stellar SDK - JavaScript SDK for Stellar
For issues and questions:
- Open an issue on GitHub
- Check the documentation
- Review the architecture guide
Built with ❤️ using Node.js and Stellar
For comprehensive documentation, see the Documentation Index.
- Pre-Deployment Checklist - Production deployment verification
- Quick Start Guide - Get started quickly
- API Examples - Complete API usage examples
- Coverage Guide - Test coverage documentation
- Mock Stellar Guide - Testing without network calls
- Versioning Strategy - SemVer rules, release flow, and breaking change policy