A backend-only RESTful API for a fintech-style digital wallet system, designed with correctness, security, and scalability in mind.
This project implements wallet management, money transfers, fraud detection, admin review workflows, and aggregated statistics with Redis caching.
- Token-based authentication using Laravel Sanctum
- Multi-currency wallet support (TRY, USD, EUR)
- Transactions: Deposit, Withdrawal, Transfer, Refund
- Atomic balance updates with database transactions and row-level locking
- Idempotency support for transfer requests
- Fee calculation using Strategy Pattern
- Rule-based fraud detection (Pipeline / Chain of Responsibility)
- Automatic transaction flagging
- Manual review workflow (pending_review)
- Multiple configurable fraud rules
- Review, approve, reject suspicious transactions
- Aggregated statistics endpoint
- Redis-based caching for heavy queries
- Redis for cache and rate limiting
- Pagination on all list endpoints
- Artisan operational commands
- Unit tests for fee logic
- Feature tests for transfer and auth flows
- PHP 8.3+
- Laravel 12
- MySQL / MariaDB
- Redis
- PHPUnit
- PHP 8.3+
- Composer
- MySQL or MariaDB
- Redis Server
- Git
git clone https://github.com/sabermand/wallet.git
cd wallet
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate.env:
CACHE_STORE=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379php artisan servephp artisan testphp artisan stats:refresh-cacheAccept: application/json
Content-Type: application/json
Authorization: Bearer {SANCTUM_TOKEN}
Transfer endpoints also require:
Idempotency-Key: {unique-key}
POST /api/v1/auth/register
{
"name": "Hamid",
"email": "hamid@example.com",
"password": "Pass1234!",
"password_confirmation": "Pass1234!"
}POST /api/v1/auth/login
{
"email": "hamid@example.com",
"password": "Pass1234!"
}POST /api/v1/wallets
{
"currency": "TRY"
}GET /api/v1/wallets
GET /api/v1/wallets/{wallet_id}/balance
POST /api/v1/transactions/deposit
{
"wallet_id": "WALLET_UUID",
"amount": 500
}POST /api/v1/transactions/withdraw
{
"wallet_id": "WALLET_UUID",
"amount": 200
}POST /api/v1/transactions/transfer
{
"source_wallet_id": "WALLET_UUID_1",
"destination_wallet_id": "WALLET_UUID_2",
"amount": 100
}GET /api/v1/admin/transactions/pending-review
POST /api/v1/admin/transactions/{id}/approve
POST /api/v1/admin/transactions/{id}/reject
GET /api/v1/admin/statistics