A modern backend API combining fintech capabilities with gamification features. Users can manage finances, perform transfers, and earn rewards through interactive gameplay.
- Overview
- Architecture
- Project Structure
- Authentication
- API Endpoints
- Database Models
- Configuration
- Getting Started
This API provides a complete fintech and gamification platform with the following capabilities:
- JWT-based authentication with Google OAuth support
- Banking system with accounts and transactions
- ATM wallet for money transfers
- Gamification with click-based rewards and timed rewards
- Contact management system
- Global leaderboard with multiple metrics
- Avatar upload with Cloudinary storage
- Support ticket system
- Radio station API
Client
|
v
app.ts (Global Middlewares)
- JWT Authentication
- File Upload (Multer)
|
├─ /api/auth ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/users ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/bank ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/atm ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/transaction ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/game ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/reward ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/leaderboard ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/contact ──> Routes ──> Controller ──> Service ──> Model ──> Database
├─ /api/radio ──> Routes ──> Controller ──> Service (Static Data)
└─ /api/support ──> Routes ──> Controller ──> Service (Email)
Routes → Controller → Service → Model → Database
| Layer | Technology |
|---|---|
| Language | TypeScript |
| Runtime | Node.js + Express |
| Database | SQL (PostgreSQL) |
| Authentication | JWT (JSON Web Tokens) |
| File Storage | Cloudinary |
| Email Service | SMTP / NodeMailer |
Backend-Devices/
│
├── src/
│ ├── app.ts # Express application setup
│ ├── server.ts # Server entry point
│ │
│ ├── config/ # Global configuration
│ │ ├── database.ts # Database connection
│ │ └── cloudinary.ts # Cloudinary configuration
│ │
│ ├── routes/ # API route definitions
│ │ ├── auth.routes.ts
│ │ ├── user.routes.ts
│ │ ├── bank.routes.ts
│ │ ├── transaction.routes.ts
│ │ ├── atm.routes.ts
│ │ ├── game.routes.ts
│ │ ├── leaderboard.routes.ts
│ │ ├── contact.routes.ts
│ │ ├── radio.routes.ts
│ │ └── support.routes.ts
│ │
│ ├── controllers/ # Request handling logic
│ │ ├── auth.controller.ts
│ │ ├── user.controller.ts
│ │ ├── bank.controller.ts
│ │ ├── transaction.controller.ts
│ │ ├── atm.controller.ts
│ │ ├── game.controller.ts
│ │ ├── leaderboard.controller.ts
│ │ ├── contact.controller.ts
│ │ ├── radio.controller.ts
│ │ └── support.controller.ts
│ │
│ ├── services/ # Business logic
│ │ ├── auth.service.ts
│ │ ├── user.service.ts
│ │ ├── bank.service.ts
│ │ ├── transaction.service.ts
│ │ ├── atm.service.ts
│ │ ├── game.service.ts
│ │ ├── leaderboard.service.ts
│ │ ├── contact.service.ts
│ │ ├── email.service.ts
│ │ ├── radio.service.ts
│ │ └── support.service.ts
│ │
│ ├── model/ # Database models (queries)
│ │ ├── auth.model.ts
│ │ ├── user.model.ts
│ │ ├── bank.model.ts
│ │ ├── transaction.model.ts
│ │ ├── atm.model.ts
│ │ ├── game.model.ts
│ │ ├── leaderboard.model.ts
│ │ └── contact.model.ts
│ │
│ ├── middlewares/ # Custom middlewares
│ │ ├── auth.middleware.ts # JWT verification
│ │ └── upload.middleware.ts # File upload handling
│ │
│ ├── types/ # TypeScript interfaces
│ │ └── auth.request.ts
│ │
│ ├── data/ # Static data
│ │ └── radio/
│ │ ├── radio.colombia.ts
│ │ ├── radio.eeuu.ts
│ │ └── radio.japan.ts
│ │
│ └── utils/ # Helper functions
│ ├── email.templates.ts
│ ├── email.utils.ts
│ └── upload.utils.ts
│
├── package.json
├── tsconfig.json
└── README.md
| Directory | Purpose |
|---|---|
| routes | Defines endpoints and maps requests to controllers |
| controllers | Handles HTTP requests and response formatting |
| services | Contains complex business logic |
| model | Database access layer with SQL queries |
| middlewares | Processes requests before reaching controllers |
| types | TypeScript interfaces and type definitions |
| config | Global configurations and connections |
| utils | Reusable helper functions |
| data | Static data and seeds |
All protected endpoints require a JWT token in the Authorization header:
Authorization: Bearer <JWT_TOKEN>
Automatic user creation on first login:
Register/Login with Google
POST /api/auth/google/register
Content-Type: application/jsonRequest Body:
{
"name": "Juan",
"lastName": "Gabriel",
"email": "juan@gmail.com",
"provider_id": "google_user_id",
"avatar": "https://..."
}Response:
{
"user": {
"user_id": 1,
"email": "juan@gmail.com",
"provider": "google"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}GET /api/users
Authorization: Bearer TOKENPUT /api/users/update
Authorization: Bearer TOKEN
Content-Type: application/jsonRequest Body:
{
"name": "Juan",
"lastName": "Perez",
"password": "newPassword123",
"avatar": "https://link-to-avatar"
}Response:
{
"user_id": 5,
"name": "Juan",
"lastName": "Perez",
"avatar": "cloudinary_url"
}POST /api/users/avatar
Authorization: Bearer TOKEN
Content-Type: multipart/form-dataForm Data: avatar: <image_file>
Response:
{
"avatar": "https://res.cloudinary.com/.../avatars/avatar123.png"
}Note: If the user already has an avatar, the previous image is deleted from Cloudinary, the new one is uploaded, and the database is updated.
Step 1: Request Reset Code
POST /api/users/request-reset
Content-Type: application/jsonRequest Body:
{
"email": "user@example.com"
}Response:
{
"message": "Code sent to email"
}Step 2: Verify Reset Code
POST /api/users/verify-code
Content-Type: application/jsonRequest Body:
{
"email": "user@example.com",
"code": "123456"
}Response:
{
"message": "Valid code"
}Step 3: Reset Password
POST /api/users/reset-password
Content-Type: application/jsonRequest Body:
{
"email": "user@example.com",
"code": "123456",
"newPassword": "newPassword123"
}Response:
{
"message": "Password updated successfully"
}DELETE /api/users/delete-account
Authorization: Bearer TOKENProcess:
- Delete all transactions
- Delete ATM wallet
- Delete bank account
- Delete user record
Response:
{
"message": "Account deleted successfully"
}GET /api/bank
Authorization: Bearer TOKENResponse:
{
"message": "Bank data obtained",
"bank": {
"bank_id": 1,
"user_id": 5,
"card": "****5678",
"balance": 15000,
"created_at": "2026-01-01T10:00:00Z"
}
}POST /api/bank/create/bank
Authorization: Bearer TOKENResponse:
{
"message": "Bank account created",
"bank": {
"bank_id": 1,
"user_id": 5,
"card": "****5678",
"balance": 0
}
}Verify bank card using last 4 digits.
POST /api/bank/verify-card-code
Content-Type: application/jsonRequest Body:
{
"last4": 5678
}The ATM wallet enables money transfers between bank account, ATM wallet, and other users.
POST /api/atm/transaction/bank
Authorization: Bearer TOKEN
Content-Type: application/jsonRequest Body:
{
"amount": 200
}POST /api/atm/transaction/atm
Authorization: Bearer TOKEN
Content-Type: application/jsonRequest Body:
{
"amount": 100
}POST /api/atm/transaction/user
Authorization: Bearer TOKEN
Content-Type: application/jsonRequest Body:
{
"phone": "3001234567",
"amount": 50
}Users earn money by accumulating clicks. Frontend batches clicks and sends them.
POST /api/game/click
Authorization: Bearer TOKEN
Content-Type: application/jsonRequest Body:
{
"clicks": 25
}Response:
{
"reward": 1248
}Details:
- Reward per click: 1 - 100
- Maximum clicks per request: 100
- Money is added directly to bank balance
Users can claim a reward every 10 minutes.
POST /api/reward/claim
Authorization: Bearer TOKENResponse (Success):
{
"reward": 3487
}Response (Not Ready):
{
"message": "Wait 420 seconds to claim reward"
}Details:
- Reward range: 1000 - 5000
- Database field:
users.last_reward
GET /api/transaction/history?page=1&limit=10&type=atm_transfer
Authorization: Bearer TOKENQuery Parameters (Optional):
page- Page number (default: 1)limit- Records per page (default: 10)type- Filter by type:bank,atm,user
Response:
[
{
"transaction_id": 30,
"user_id": 5,
"receiver_user_id": 8,
"amount": 50,
"type": "atm_transfer",
"created_at": "2026-01-15T10:30:00Z"
}
]Transaction Types:
bank- Bank transferatm- ATM transferuser- User-to-user transfer
Users can claim a reward every 10 minutes.
Reward range:
1000 - 5000
Endpoint
POST /reward/claim
Headers
Authorization: Bearer TOKEN
Response
{
"reward": 3487
}If the user tries too early:
{
"message": "Wait 420 seconds to claim reward"
}Database field used:
users.last_reward
POST /support
{
"message": "Message sent successfully",
"emailSent"
}Images are stored in folders:
avatars/
products/
Example URL:
https://res.cloudinary.com/.../image/upload/v123/avatars/avatar123.png
Public ID extracted:
avatars/avatar123
Used for deletion:
cloudinary.uploader.destroy(public_id)
Returns a list of radio stations from Colombia, United States and Japan,.
Base endpoint:
/api/radio
Radio from Colombia:
GET /api/radio/colombia
Radio from United States:
GET /api/radio/eeuu
Radio from Japan:
GET /api/radio/japan
Provides ranked views of users based on different metrics.
- bank_balance
- atm_balance
- total_balance
- total_transactions
- total_contacts
All rankings are paginated in chunks of 50.
Returns ranked users ordered by a selected metric.
GET /api/leaderboard
?metric=total_transactions
order=DESC
page=0
{
"user_id": 1,
"name": "Diego",
"lastname": "Rojas",
"bank_balance": 10000,
"atm_balance": 5000,
"total_balance": 15000,
"total_transactions": 320,
"total_contacts": 45
}Returns the authenticated user’s position in a given metric.
GET /leaderboard/me/rank
metric=total_transactions
order=DESC
Authorization: Bearer TOKEN
{
"rank": 342
}Returns users around the authenticated user in the ranking.
GET /leaderboard/me/context
metric=total_transactions
Authorization: Bearer TOKEN
{
"rank": 342,
"data": [
{
"user_id": 10,
"name": "User A",
"total_transactions": 120
},
{
"user_id": 15,
"name": "YOU",
"total_transactions": 88
},
{
"user_id": 18,
"name": "User B",
"total_transactions": 80
}
]
}Contacts System
Users can manage a personal contacts list linked to existing system users.
A contact can only be created if the phone number exists in the users table.
Each contact requires a custom display name (name_contact).
Returns all contacts of the authenticated user, with optional search by name or phone.
GET /api/contact
/api/contact?search=string
Authorization: Bearer TOKEN
{
"contact_id": 1,
"phone": "3123456789",
"name_contact": "Juan Oficina",
"created_at": "2026-04-11T10:00:00Z"
}Adds a new contact linked to an existing user by phone.
POST /contact
Authorization: Bearer TOKEN
{
"phone": "3123456789",
"name_contact": "Juan Oficina"
}-
name_contact is required
-
phone must exist in users.phone
-
duplicates per user are not allowed
{
"contact_id": 1,
"phone": "3123456789",
"name_contact": "Juan Oficina",
"created_at": "2026-04-11T10:00:00Z"
}Error (user does not exist)
{
"message": "User does not exist"
}Error (missing name)
{
"message": "Contact name is required"
}Updates only the custom contact name.
PATCH /api/contact
Authorization: Bearer TOKEN
{
"name_contact": "Nuevo Nombre"
}{
"success": true
}Only name_contact can be updated Contact must belong to authenticated user
#Delete Contact
Removes a contact from the user’s list.
DELETE /contact/:contact_id
Authorization: Bearer TOKEN
{
"success": true
}Alternative explicit search endpoint.
GET /contact/search?q=string
Authorization: Bearer TOKEN
{
"contact_id": 1,
"phone": "3123456789",
"name_contact": "Juan Oficina"
}src
├ config
├ controllers
├ data
├ middleware
├ model
├ routes
├ services
├ types
├ utils
├ app.ts
└ server.ts
- Node.js 14 or later
- npm or yarn
- PostgreSQL or MySQL database
- Cloudinary account
- Google OAuth credentials (if using Google Login)
- Clone the repository:
git clone <repository-url>
cd Backend-Devices- Install dependencies:
npm install-
Create or update your environment variables.
-
Start the development server:
npm run dev- Start the production server:
npm startCreate a .env file in the project root and configure the following values:
DB_HOST=localhost
DB_PORT=5432
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_NAME=your_db_name
JWT_SECRET=your_jwt_secret
CLOUDINARY_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_cloudinary_api_key
CLOUDINARY_API_SECRET=your_cloudinary_api_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_smtp_user
SMTP_PASSWORD=your_smtp_password
PORT=5000The API includes:
- JWT Authentication
- Google Login
- Avatar Upload with Cloudinary
- User Update
- Account Deletion
- Bank & ATM System
- Phone Transfers
- Contact system
- Leaderboard system
- Transaction History
- Click Game Rewards
- Timed Rewards
- Radio Stations
This backend works as a mini fintech + game reward system.