Automated Birthday Wishes API Documentation
Created by: Suresh Shrestha
Last updated: March 2, 2025
How It Works?
1️⃣ User data is collected via a frontend application (React in my case) ⚛️

2️⃣ The backend (Node.js & Express) processes the data and stores user details (first name, last name (optional), birth date, email, phone) in MongoDB 🔑
3️⃣ A cron job runs daily (via GitHub Actions) to check for birthdays ⏰
4️⃣ The backend fetches birthday users and sends emails automatically using Nodemailer 📧



Overview
This API provides user authentication, API key management, and user management functionalities. Users can sign up, log in, retrieve their API key, change passwords, regenerate their API key, and manage user information.
Tech Stack
Backend: Node.js, Express, MongoDB
Frontend: React, Tailwind CSS
Automation: Cron jobs via GitHub Actions
Messaging: Emails via Nodemailer, and SMS via Twilio
All Free Resources Used:
✅ MongoDB Atlas – Free database hosting
✅ Render.com – Free Node.js backend hosting (https://bday-787u.onrender.com)
✅ Netlify – Free React frontend hosting (https://birthdaymails.netlify.app, BirthdayMails API Console)
✅ GitHub Actions – Free CI/CD & cron job scheduler
✅ Nodemailer (Gmail SMTP) – Free email sending
I planned to enable SMS via Twilio, but since it’s a paid service, I haven’t activated it yet.
Security:
Authentication
The API uses API Key authentication. Users receive an API key upon signup, which they can use for future authentication. API key is passed in the request headers.
const authHeader = req.header("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return res.status(401).json({ error: "API key is required" });
}
The API key is sent in the authorization header using the Bearer scheme.
Example request:
GET /users/all
Authorization: Bearer YOUR_API_KEY
Authorization
The API uses role-based authorization, ensuring only authorized users can access certain features.
Database Connection
The API uses MongoDB as its database. Connection is established via the connectDB function:
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log('✅ MongoDB Connected');
} catch (error) {
console.error('❌ MongoDB connection error:', error);
process.exit(1);
}
};
module.exports = connectDB;
In my database, I have two collections:
1. apiusers Collection
- This stores details about user who interact with my API. It includes these fields: _id, email(string), password(string), apikey(string), role(string)
2. users Collection
- This stores general user information. It inculcates these fields: _id, firstName(string), lastName(string), birthdate(date), email(string), phone(string), subscribed(boolean)
API User Routes & Their Functions:
SN 128_041dc8-e2> |
Routes 128_686a3e-3c> |
Function 128_36579d-80> |
---|---|---|
1 128_38373c-ef> |
POST /api/auth/signup 128_8cc8b3-ae> |
Registers a new user and generates an API key. 128_0279a4-ae> |
2 128_b975e9-24> |
POST /api/auth/login 128_933644-ed> |
Logs in a user and returns their API key. 128_bb8adf-32> |
3 128_e01825-aa> |
PUT /api/auth/change-password 128_96c138-fb> |
Allows users to change their password. 128_701d8f-cf> |
4 128_fccf41-73> |
PUT /api/auth/regenerate-key 128_845a60-22> |
Allows users to regenerate a new API key. 128_b7642e-1e> |
5 128_f7ce79-0a> |
POST /api/auth/get-key 128_8fbb69-09> |
Allows users to retrieve their API key if forgotten. 128_d773e5-9d> |
6 128_1acc9c-21> |
DELETE /api/auth/delete 128_d06094-6e> |
Deletes a user’s account. 128_47f3e0-16> |

1. API User Signup
Endpoint: POST /api/auth/signup
Request Body:
{
"email": "user@example.com",
"password": "secure*Password54"
}
Success Response:
{
"message": "API Key generated",
"apiKey": "generated-api-key"
}
2. API User Login
Endpoint: POST /api/auth/login
Request Body:
{
"email": "user@example.com",
"password": "secure*Password54"
}
Success Response:
{
"message": "Login successful",
"apiKey": "user-api-key"
}
3. Change API User Password
Endpoint: PUT /api/auth/change-password
Request Body:
{
"email": "user@example.com",
"currentPassword": "oldpassword",
"newPassword": "newsecurepassword"
}
Success Response:
{
"message": "Password changed successfully"
}
4. Regenerate API Key
Endpoint: PUT /api/auth/regenerate-key
Request Body:
{
"email": "user@example.com",
"password": "secure*Password54"
}
Success Response:
{
"message": "New API Key generated",
"apiKey": "new-api-key"
}
5. Retrieve API Key
Endpoint: POST /api/auth/get-key
Request Body:
{
"email": "user@example.com",
"password": "secure*Password54"
}
Success Response:
{
"apiKey": "user-api-key"
}
6. Delete API Key
Endpoint: DELETE /api/auth/delete
Request Body:
{
"email": "user@example.com",
"password": "secure*Password54"
}
Success Response:
{
"message": "API user deleted successfully"
}
Birthday Users API Routes & Their Functions:
SN 128_9d4420-ab> |
Routes 128_91179e-ac> |
Function 128_4988e1-fb> |
---|---|---|
1 128_347b11-db> |
POST /users/add 128_e12ed2-48> |
Add a user with first name, last name, email, birthday, email, phone 128_68724c-13> |
2 128_7ad4d7-b8> |
PUT /users/update/:id 128_c1c2b7-43> |
Update user details 128_17635d-23> |
3 128_777487-c9> |
DELETE /users/delete/:id 128_cbba94-9d> |
Remove a user 128_2c3fdb-b8> |
4 128_963563-7f> |
GET /users/all 128_bc35bd-df> |
Retrieve all users 128_50e4d9-0f> |
5 128_b82c0a-be> |
PUT /users/subscribe/:id 128_b9d58b-c9> |
Subscribe user to email and SMS 128_eafb63-05> |
6 128_66da01-ec> |
PUT /users/unsubscribe/:id 128_2d322c-ec> |
Unsubscribe user from email and SMS 128_c76c20-0b> |
1. Add User
Endpoint: POST /users/add
Request Body:
{
"firstName": "John",
"lastName": "Doe",
"birthdate": "2000-12-25",
"email": "john@example.com",
"phone": "1234567890",
"recaptchaToken": "recaptcha-token"
}
Success Response:
{
"message": "User added successfully!"
}
2. Update User
Endpoint: PUT /users/update/:id
Request Body:
{
"firstName": "Jane",
"lastName": "Doe",
"birthdate": "2002-01-01",
"email": "jane@example.com",
"phone": "9876543210"
}
Success Response:
{
"message": "User updated successfully",
"user": { "updated-user-data" }
}
3. Delete User
Endpoint: DELETE /users/delete/:id
Success Response:
{
"message": "User deleted successfully"
}
4. Get All Users
Endpoint: GET /users/all
Success Response:
[
{
"_id": "67b96317e47490f6d728e00d",
"firstName": "John",
"lastName": "Doe",
"birthdate": "2000-12-25",
"email": "john@example.com",
"phone": "+1234567890",
"subscribed": true,
"createdAt": "2025-02-22T05:22:38.275Z"
},
{
"_id": "67b96317e47420f4d728e00f",
"firstName": "Jane",
"lastName": "Doe",
"birthdate": "2002-01-01",
"email": "jane@example.com",
"phone": "+9876543210",
"subscribed": false,
"createdAt": "2025-02-24T05:22:38.275Z"
},
]
5. Subscribe User to Email & SMS
Endpoint: PUT /users/subscribe/:id
Success Response:
{
"message": "User subscribed successfully"
}
6. Unsubscribe User from Email & SMS
Endpoint: Get /users/unsubscribe/:id
Endpoint: PUT /users/unsubscribe/:id
This does not return JSON but rather updates the subscription status and redirects, the response to a PUT request will be:
If the user is found and unsubscribed:
HTTP 302 (Redirect)
Location: <REDIRECT_URL>/unsubscribe?status=success&id=<user_id>
If the user is not found:
HTTP 302 (Redirect)
Location: <REDIRECT_URL>/unsubscribe?status=not_found
If there is an error (e.g., database issue):
HTTP 302 (Redirect)
Location: <REDIRECT_URL>/unsubscribe?status=error
Security: API Key & Role-Based Authorization
Every API request requires an API key for authentication.
I wanted to ensure that only the super admin has permission to view all users, remove a user, and update existing user information. Since birthday user data includes sensitive personal details like birth-dates and phone numbers, I implemented these restrictions to protect user privacy and prevent unauthorized access.
Route 128_84b00d-54> |
Requires Auth? 128_570f0b-1c> |
Allowed Roles 128_04c171-27> |
---|---|---|
POST /users/add 128_a52a00-9b> |
✅ Yes 128_2ff757-a2> |
admin, superadmin 128_4b8b8d-ec> |
PUT /users/update/:id 128_cadd41-01> |
✅ Yes 128_583f90-17> |
superadmin 128_0303b7-52> |
DELETE /users/delete/:id 128_4c0a9f-b9> |
✅ Yes 128_3db0a6-97> |
superadmin 128_61ebe0-de> |
GET /users/all 128_497d2a-d0> |
✅ Yes 128_527d82-c2> |
superadmin 128_abec61-f5> |
PUT /users/subscribe/:id 128_5c8bcd-53> |
✅ Yes 128_797c5d-bc> |
admin, superadmin 128_70a366-53> |
PUT /users/unsubscribe/:id 128_647a23-15> |
✅ Yes 128_95fa4f-37> |
admin, superadmin 128_717628-14> |
GET /users/unsubscribe/:id 128_50ace0-ca> |
❌ No 128_cd2230-84> |
Public 128_3e83bc-c8> |