A secure, production-ready wallet transaction API with user authentication, two-phase debit authorization, HMAC request signing, and comprehensive admin controls.
- User Registration & Authentication - Complete auth flow with JWT tokens
- Role-Based Access Control (RBAC) - Customer and Admin roles
- Customer Wallet APIs - Deposit, withdraw, view balance and transactions
- Admin Controls - Freeze wallets, reverse transactions, platform oversight
- Two-Phase Debit Authorization - Authorize → Debit/Reverse pattern for safe fund holds
- Rate Limiting - Comprehensive rate limiting to protect against abuse
- Batch Transactions - Atomic processing of multiple transactions
- Transaction History - Advanced filtering and sorting capabilities
- Webhook Notifications - Real-time event notifications for transactions
- Multi-Currency Support - 10 major currencies with automatic conversion
- HMAC-SHA256 Request Signing - Cryptographic request integrity verification
- Replay Protection - Nonce-based protection against duplicate requests
- Idempotent Operations - Safe retry handling with referenceId tracking
- Precision Math - Financial calculations using
monetrav2.3.0 for accuracy - Full Audit Trail - Complete ledger with balance snapshots
- Serverless Ready - AWS Lambda compatible via serverless-http
- Terminology
- Quick Start
- API Endpoints
- cURL Examples
- Authentication
- Transaction Flow
- Project Structure
- Documentation
- Testing
- Contributing
- License
Understanding the transaction terminology used in this API:
| Term | Alias | Description |
|---|---|---|
| Authorize | Reserve | Places a hold on funds without transferring them. The amount is reserved but still belongs to the wallet. |
| Debit | Capture | Completes a previously authorized transaction, actually transferring the reserved funds. |
| Credit | Add | Adds funds directly to a wallet balance. |
| Reverse | Release/Undo | Cancels a pending authorization, releasing the held funds back to available balance. |
| Deposit | - | Customer-initiated credit to their own wallet. |
| Withdraw | - | Customer-initiated debit from their own wallet. |
| Freeze | Lock | Admin action to prevent all transactions on a wallet. |
| Unfreeze | Unlock | Admin action to restore normal wallet operations. |
| State | Description |
|---|---|
pending |
Authorization created, funds reserved but not captured |
completed |
Transaction finalized, funds transferred |
reversed |
Authorization cancelled, funds released |
- Node.js 20.x or higher
- MySQL 8.x or MariaDB 10.x
- Redis 7.x
# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install dependencies
brew install node@20 mysql redis
# Start services
brew services start mysql
brew services start redis
# Clone and setup project
git clone https://github.com/zugobite/wallet.git
cd wallet
npm install
cp .env.example .env
npm run prisma:generate
npm run prisma:migrate
npm run dev# Install Node.js 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# Install MySQL
sudo apt-get install -y mysql-server
sudo systemctl start mysql
# Install Redis
sudo apt-get install -y redis-server
sudo systemctl start redis
# Clone and setup project
git clone https://github.com/zugobite/wallet.git
cd wallet
npm install
cp .env.example .env
npm run prisma:generate
npm run prisma:migrate
npm run dev# Install Chocolatey if not already installed (run as Administrator)
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install dependencies
choco install nodejs-lts mysql redis-64
# Start services (run as Administrator)
net start mysql
net start redis
# Clone and setup project
git clone https://github.com/zugobite/wallet.git
cd wallet
npm install
copy .env.example .env
npm run prisma:generate
npm run prisma:migrate
npm run dev# Clone the repository
git clone https://github.com/zugobite/wallet.git
cd wallet
# Install dependencies
npm install
# Copy environment template
cp .env.example .env
# Edit .env with your configuration
# Generate Prisma client
npm run prisma:generate
# Run database migrations
npm run prisma:migrate
# Start the server
npm run devThe server will start at http://localhost:3000.
curl http://localhost:3000/health# macOS - Check if Redis is running
brew services list | grep redis
# Start Redis if not running
brew services start redis
# Ubuntu/Debian
sudo systemctl status redis
sudo systemctl start redis# Check MySQL status
# macOS
brew services list | grep mysql
# Ubuntu/Debian
sudo systemctl status mysql
# Verify connection
mysql -u root -p -e "SELECT 1;"| Error | Solution |
|---|---|
ECONNREFUSED 127.0.0.1:6379 |
Redis is not running. Start with brew services start redis or sudo systemctl start redis |
ECONNREFUSED 127.0.0.1:3306 |
MySQL is not running. Start with brew services start mysql or sudo systemctl start mysql |
P1001: Can't reach database |
Check DATABASE_URL in .env, ensure MySQL is running |
assertNonNegative is not exported |
Update monetra to v2.1.0: npm install monetra@^2.1.0 |
Interactive API documentation is available via Swagger UI.
Start the server and visit:
http://localhost:3000/api-docs
This provides:
- Interactive Testing - Execute requests directly from the browser
- Schema Definitions - detailed models of inputs and outputs
- Authentication - visual interface for Bearer token authorization
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check (no auth) |
GET |
/health/live |
Liveness probe (Kubernetes) |
GET |
/health/ready |
Readiness probe (Kubernetes) |
GET |
/api/v1 |
API information (no auth) |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/register |
Register new user |
POST |
/api/v1/auth/login |
Login and get token |
GET |
/api/v1/auth/me |
Get current user |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/wallets/:id |
Get wallet details |
GET |
/api/v1/wallets/:id/balance |
Get wallet balance |
GET |
/api/v1/wallets/:id/transactions |
Get transaction history |
POST |
/api/v1/wallets/:id/deposit |
Deposit funds |
POST |
/api/v1/wallets/:id/withdraw |
Withdraw funds |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/transactions/authorize |
Create pending authorization |
POST |
/api/v1/transactions/debit |
Complete debit transaction |
POST |
/api/v1/transactions/credit |
Direct credit to wallet |
POST |
/api/v1/transactions/reverse |
Reverse pending authorization |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/admin/users |
List all users |
GET |
/api/v1/admin/wallets |
List all wallets |
GET |
/api/v1/admin/transactions |
List all transactions |
POST |
/api/v1/admin/wallets/:id/freeze |
Freeze a wallet |
POST |
/api/v1/admin/wallets/:id/unfreeze |
Unfreeze a wallet |
POST |
/api/v1/admin/transactions/:id/reverse |
Admin reverse transaction |
Run the Jest unit test suite:
npm testRun the comprehensive cURL-based E2E test suite to verify all flows against a running server:
# 1. Start the server
npm run dev
# 2. Run the test script (in a separate terminal)
./tests/e2e/run_curl_flows.shThe E2E script tests:
- User Registration & Login
- Wallet Details & Balance Checks
- Deposits & Withdrawals
- Two-Phase Transactions (Authorize & Debit)
- Transaction Reversal
- Transaction History
curl -X POST http://localhost:3000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "demo@example.com",
"password": "SecurePassword123!"
}'curl -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "demo@example.com",
"password": "SecurePassword123!"
}'curl -X GET "http://localhost:3000/api/v1/wallets/YOUR_WALLET_ID/balance" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"curl -X POST "http://localhost:3000/api/v1/wallets/YOUR_WALLET_ID/deposit" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"amount": 10000,
"referenceId": "deposit-001"
}'curl -X POST "http://localhost:3000/api/v1/wallets/YOUR_WALLET_ID/withdraw" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"amount": 2500,
"referenceId": "withdraw-001"
}'curl -X GET "http://localhost:3000/api/v1/wallets/YOUR_WALLET_ID/transactions" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"# 1. Register
curl -X POST http://localhost:3000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "SecurePass123!"}'
# Save from response:
export TOKEN="your-jwt-token"
export WALLET_ID="your-wallet-id"
# 2. Deposit funds
curl -X POST "http://localhost:3000/api/v1/wallets/$WALLET_ID/deposit" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"amount": 10000, "referenceId": "deposit-001"}'
# 3. Check balance
curl -X GET "http://localhost:3000/api/v1/wallets/$WALLET_ID/balance" \
-H "Authorization: Bearer $TOKEN"
# 4. Withdraw
curl -X POST "http://localhost:3000/api/v1/wallets/$WALLET_ID/withdraw" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"amount": 2500, "referenceId": "withdraw-001"}'
# 5. View history
curl -X GET "http://localhost:3000/api/v1/wallets/$WALLET_ID/transactions" \
-H "Authorization: Bearer $TOKEN"# Login as admin
curl -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com", "password": "AdminPass123!"}'
export ADMIN_TOKEN="admin-jwt-token"
# List all users
curl -X GET "http://localhost:3000/api/v1/admin/users" \
-H "Authorization: Bearer $ADMIN_TOKEN"
# List all wallets
curl -X GET "http://localhost:3000/api/v1/admin/wallets" \
-H "Authorization: Bearer $ADMIN_TOKEN"
# Freeze a suspicious wallet
curl -X POST "http://localhost:3000/api/v1/admin/wallets/WALLET_ID/freeze" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-d '{"reason": "Suspicious activity"}'
# Reverse a fraudulent transaction
curl -X POST "http://localhost:3000/api/v1/admin/transactions/TXN_ID/reverse" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-d '{"reason": "Customer refund"}'The API uses JWT (JSON Web Token) authentication. Include the token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
| Role | Description | Access |
|---|---|---|
| CUSTOMER | Regular user | Own wallets and transactions only |
| ADMIN | Platform administrator | All users, wallets, and transactions |
For high-security environments, requests can be signed using HMAC-SHA256. See Authentication docs for details.
┌─────────┐ ┌───────────┐ ┌─────────┐
│ Client │────▶│ Authorize │────▶│ PENDING │
└─────────┘ └───────────┘ └────┬────┘
│
┌──────────────────┴──────────────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ Debit │ │ Reverse │
└─────┬─────┘ └─────┬─────┘
▼ ▼
┌───────────┐ ┌───────────┐
│ COMPLETED │ │ REVERSED │
└───────────┘ └───────────┘
- Authorize - Create a pending hold on funds
- Debit - Complete the transaction and deduct funds
- Reverse - Cancel the authorization and release hold
- Deposit - Credits are applied immediately
- Withdraw - Debits are applied immediately
wallet/
├── src/
│ ├── app.mjs # Application entry point
│ ├── routes.mjs # Route definitions
│ ├── domain/ # Business logic
│ │ ├── wallet.mjs
│ │ └── transactions.mjs
│ ├── handlers/ # Request handlers
│ │ ├── auth/ # Register, login, me
│ │ ├── wallets/ # Wallet operations
│ │ ├── admin/ # Admin operations
│ │ ├── authorize.mjs
│ │ ├── debit.mjs
│ │ ├── credit.mjs
│ │ └── reverse.mjs
│ ├── services/ # Service layer
│ │ ├── auth.service.mjs
│ │ ├── wallet.service.mjs
│ │ └── transaction.service.mjs
│ ├── middleware/ # Express middleware
│ │ ├── auth.mjs
│ │ ├── rbac.mjs # Role-based access control
│ │ ├── idempotency.mjs
│ │ ├── signature.mjs
│ │ ├── requestLogger.mjs
│ │ └── healthCheck.mjs
│ ├── infra/ # Infrastructure
│ │ ├── prisma.mjs
│ │ ├── redis.mjs
│ │ ├── logger.mjs
│ │ ├── metrics.mjs
│ │ ├── alerting.mjs
│ │ └── repositories/
│ └── utils/
│ └── canonicalJson.mjs
├── prisma/
│ └── schema.prisma # Database schema
├── tests/ # Test suite (201 tests)
├── docs/ # Documentation
└── package.json
Comprehensive documentation is available in the /docs directory:
| Document | Description |
|---|---|
| 001-PROJECT_OVERVIEW.md | Architecture and design decisions |
| 002-GETTING_STARTED.md | Setup, configuration, and quick start |
| 003-API_REFERENCE.md | Complete API docs with cURL examples |
| 004-AUTHENTICATION.md | Auth, RBAC, and signing details |
| 005-DATABASE_SCHEMA.md | Data model documentation |
| 006-TESTING.md | Testing guide |
| 007-DEPLOYMENT.md | Deployment instructions |
| 008-MONITORING.md | Logging, metrics & alerting |
| 009-SCALING.md | Scaling to 100M+ transactions |
# Run all tests (201 tests)
npm test
# Run unit tests only
npm run test:unit
# Run E2E tests
npm run test:e2e
# Run tests in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverage- Unit Tests - Domain logic, middleware, services, repositories
- E2E Tests - Health endpoint, API flow verification
# Start development server
npm run dev
# Lint code
npm run lint
# Format code
npm run format
# Open Prisma Studio (database GUI)
npm run prisma:studio| Variable | Description | Required |
|---|---|---|
DATABASE_URL |
MySQL connection string | Yes |
DATABASE_ADAPTER_URL |
MariaDB adapter URL | Yes |
REDIS_URL |
Redis connection string | Yes |
JWT_SECRET |
JWT signing secret (64+ bytes) | Yes |
REQUEST_SIGNING_SECRET |
HMAC signing secret (64+ bytes) | Yes |
SIGNATURE_TTL_MS |
Request validity window (ms) | Yes |
PORT |
Server port (default: 3000) | No |
See .env.example for a complete template.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow the existing code style
- Write tests for new features
- Update documentation as needed
- Keep commits atomic and well-described
This project is created purely for educational and portfolio demonstration purposes to showcase my knowledge of financial transaction systems and software architecture.
Important notices:
- It implements industry-standard patterns documented in publicly available resources including:
- Stripe's API design guidelines
- Martin Fowler's enterprise architecture patterns
- PCI-DSS compliance frameworks
- RFC standards (JWT, HMAC, etc.)
- This is not intended for production use without proper security audits, compliance reviews, and regulatory approvals
This project is licensed under the MIT License - see the LICENSE file for details.