Question
1.Customer logs onto Cure fit App to purchase a meal
Curefit confirms the meal selection and redirects to Razorpay for collecting money.
User enters the credit card details on Razorpay payment page
Razorpay communicates with the Bank, 2FA authentication happens.
Razorpay sends a response back to curefit, the user then gets a confirmation message from CureFit.
Curefit wants to roll out a subscription product where users select a plan (weekly, monthly, etc).Each plan has a different pricing. Razorpay has to build a subscription product which enables Curefit to collect money on a recurring basis. For example, If a user selects “Veg meal lunch daily” as a monthly plan for 1 year, he will be charged at the beginning of every month (Jan 1, Feb 1, March 1) till the ending date. Your ask is to build the Subscription product on top of the Payment system.
FR
1.Users must be able to view and select subscription plans (e.g., weekly, monthly, yearly) with details such as pricing, billing frequency, and benefits.
2.CureFit can create and manage different plans with varying pricing and billing intervals.
3.Allow CureFit to create subscriptions for users based on the selected plan.
4.Users or CureFit can pause and resume subscriptions (e.g., during vacations).
5.Enable users to switch plans mid-cycle (e.g., from weekly to monthly).
6.When a subscription is created, Razorpay must securely store the user's payment method (e.g., credit card, UPI).
7.Razorpay should handle recurring payments on the billing date without re-entering payment details.
8.Payment should be idempotent in nature
NFR
1.The system should handle high volume transactions efficiently, e.g., supporting millions of users subscribing to plans and processing recurring payments daily.
2.The platform should scale horizontally to support increased load during peak times (e.g., end-of-month payments).
3.System should be highly available
4.The platform should ensure that no subscription or payment event is lost, even during failures.
5.Failed payment retries should occur without introducing delays for subsequent users.
6.System should be eventual consistent.
System should have low latency in all non-payment api’s and considerate for payment api’s
Estimates
User Base:
CureFit has 10 million active users.
10% of users will subscribe to the service (100,000 subscriptions).
read:write = 1:1
write=10^7/10^5=100 QPS
each user does 10 subscriptions = 100*10=1k QPS
read will be same as write
1k*1kB=1MB
10M*1KB= 10GB*400(~365)=4TB/year
Users subscribe to weekly, monthly, or yearly plans.
On average, each user will make 1 payment per month.
Growth Rate:
The user base grows by 10% per year.
Storage Needs:
Each subscription record (user + plan details) is 1 KB.
Each payment transaction record is 500 bytes.
Notifications:
Each subscription generates 2 notifications per billing cycle (e.g., upcoming payment reminder and confirmation after successful payment).
Subscription storage
Current: 100,000 subscriptions.
After 1 year (10% growth): 100,000×1.1=110,000 subscriptions.
110k*1KB=110MB
API’s
1.POST api/v1/users
request {
"user_id": "12345",
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+919876543210"
}
response {
"user_id": "12345",
"status": "success"
}
2.GET api/v1/users/{user_id}
{
"user_id": "12345",
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+919876543210",
"subscriptions": ["sub_001", "sub_002"]
}
4.POST api/v1/subscriptions
request {
"user_id": "12345",
"plan_id": "plan_001",
"start_date": "2025-01-01",
"billing_cycle": "monthly",
"duration": "12", // in months
"payment_method": "card",
"card_details": {
"card_number": "4111111111111111",
"expiry_month": "12",
"expiry_year": "2028",
"cvv": "123"
}
}
response {
"subscription_id": "sub_001",
"status": "active",
"next_billing_date": "2025-02-01"
}
5.PUT api/v1/subscriptions/{subscription_id}
Update an existing subscription (e.g., change plan or payment method).
request {
"plan_id": "plan_002",
"payment_method": "upi",
"upi_id": "john.doe@upi"
}
response {
"plan_id": "plan_002",
"payment_method": "upi",
"upi_id": "john.doe@upi"
}
6.DELETE api/v1/subscriptions/{subscription_id}
{
"subscription_id": "sub_001",
"status": "cancelled"
}
7.GET api/v1/subscriptions/{subscription_id}
Retrieve details of a subscription.
{
"subscription_id": "sub_001",
"user_id": "12345",
"plan_id": "plan_001",
"status": "active",
"next_billing_date": "2025-02-01",
"created_at": "2025-01-01",
"billing_cycle": "monthly",
"duration": "12"
}
POST api/v1/plan
request { "plan_id": "plan_001", "name": "Veg Meal Lunch Daily - Monthly", "price": 2000, "billing_cycle": "monthly", "duration": "12", // in months "description": "Daily veg lunch delivered to your home" } response { "plan_id": "plan_001", "status": "created" }
9.GET api/v1/plans/{plan_id}
{
"plan_id": "plan_001",
"name": "Veg Meal Lunch Daily - Monthly",
"price": 2000,
"billing_cycle": "monthly",
"duration": "12",
"description": "Daily veg lunch delivered to your home"
}
10.POST api/v1/payments
request {
"subscription_id": "sub_001",
"amount": 2000,
"payment_method": "card",
"card_details": {
"card_number": "4111111111111111",
"expiry_month": "12",
"expiry_year": "2028",
"cvv": "123"
}
}
response {
"payment_id": "pay_001",
"status": "success",
"transaction_date": "2025-01-01"
}
POST api/v1/payments/{payment_id}/retry
{ "payment_id": "pay_001", "status": "success" }
12.GET api/v1/payments/{payment_id}
{
"payment_id": "pay_001",
"subscription_id": "sub_001",
"amount": 2000,
"status": "success",
"transaction_date": "2025-01-01"
}
13.POST api/v1/notifications
request {
"user_id": "12345",
"type": "payment_success",
"message": "Your payment of ₹2000 for the Veg Meal Lunch subscription was successful.",
"metadata": {
"subscription_id": "sub_001",
"payment_id": "pay_001"
}
}
response {
"notification_id": "notif_001",
"status": "sent"
}
GET api/v1/users/{user_id}/subscriptions
[ { "subscription_id": "sub_001", "plan_id": "plan_001", "status": "active", "created_at": "2025-01-01", "next_billing_date": "2025-02-01" }, { "subscription_id": "sub_002", "plan_id": "plan_002", "status": "cancelled", "created_at": "2024-06-01", "cancelled_at": "2024-12-01" } ]
Databases
The subscription platform requires a combination of databases to handle different use cases effectively:
1. Databases to Use
Relational Database (e.g., PostgreSQL, MySQL):
Best suited for structured data like user details, subscriptions, plans, and payments.
Supports ACID transactions to ensure consistency for critical operations like payments.
NoSQL Database (e.g., MongoDB, DynamoDB):
For unstructured or semi-structured data like notification logs, webhooks, and metadata.
Caching (e.g., Redis, Memcached):
For storing frequently accessed data like active subscriptions, plan details, or user details to improve response times.
Message Queue (e.g., RabbitMQ, Kafka):
To manage asynchronous tasks like sending notifications or processing payment retries.
2. Schema Design
Here’s a detailed schema for the system:
1. Users Table
Purpose: Stores user information.
Database: Relational (PostgreSQL/MySQL)
CREATE TABLE users (
user_id VARCHAR(36) PRIMARY KEY, -- UUID for unique user identification
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(15) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(), -- Timestamp for user creation
updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
);
2. Plans Table
Purpose: Stores details of subscription plans.
Database: Relational (PostgreSQL/MySQL)
CREATE TABLE plans (
plan_id VARCHAR(36) PRIMARY KEY, -- UUID for unique plan identification
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL, -- Plan price
billing_cycle ENUM('weekly', 'monthly', 'yearly') NOT NULL,
duration INT NOT NULL, -- Duration of the plan (in months)
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
);
3. Subscriptions Table
Purpose: Stores user subscriptions.
Database: Relational (PostgreSQL/MySQL)
CREATE TABLE subscriptions (
subscription_id VARCHAR(36) PRIMARY KEY, -- UUID for unique subscription ID
user_id VARCHAR(36) NOT NULL, -- FK to users table
plan_id VARCHAR(36) NOT NULL, -- FK to plans table
start_date DATE NOT NULL, -- Subscription start date
next_billing_date DATE NOT NULL, -- Next billing date
status ENUM('active', 'cancelled', 'expired') DEFAULT 'active',
payment_method ENUM('card', 'upi', 'net_banking') NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW(),
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (plan_id) REFERENCES plans(plan_id)
);
4. Payments Table
Purpose: Logs all payment transactions.
Database: Relational (PostgreSQL/MySQL)
CREATE TABLE payments (
payment_id VARCHAR(36) PRIMARY KEY, -- UUID for unique payment ID
subscription_id VARCHAR(36) NOT NULL, -- FK to subscriptions table
amount DECIMAL(10, 2) NOT NULL, -- Payment amount
status ENUM('success', 'failed', 'pending') DEFAULT 'pending',
transaction_date TIMESTAMP DEFAULT NOW(), -- Payment timestamp
payment_method ENUM('card', 'upi', 'net_banking') NOT NULL,
failure_reason TEXT, -- Reason for payment failure (if any)
FOREIGN KEY (subscription_id) REFERENCE{
"notification_id": "notif_001",
"user_id": "12345",
"type": "payment_success", // e.g., payment_success, payment_failed
"message": "Your payment of ₹2000 was successful.",
"metadata": {
"subscription_id": "sub_001",
"payment_id": "pay_001"
},
"status": "sent", // sent, failed, pending
"created_at": "2025-01-01T10:00:00Z"
}
S subscriptions(subscription_id)
);
Interaction Flow for Subscription Creation
User selects a plan on the CureFit app.
CureFit calls the
Subscription Service
to create a subscription.The
Subscription Service
:Validates the user by calling the
User Service
.Validates the plan by calling the
Plan Service
.Calls the
Payment Service
to process the first payment and tokenize the card.
The
Payment Service
integrates with Razorpay for:Payment Authorization.
Tokenization for recurring payments.
Once the payment succeeds:
The
Subscription Service
schedules recurring payments.Sends a success message to the
Notification Service
to inform the user.
Interaction Flow for Recurring Payments
The
Subscription Service
triggers a recurring payment event on the billing date.The
Payment Service
:Processes the recurring payment using the tokenized card (via Razorpay).
If payment succeeds:
The
Notification Service
sends a success notification to the user.
If payment fails:
The
Payment Service
retries the payment and notifies theNotification Service
of failure.
Interaction Flow for Razorpay Webhooks
Razorpay sends a webhook event (e.g., payment success/failure) to the
Webhook Service
.The
Webhook Service
:Processes the event and updates the
Payment Service
.Updates the
Subscription Service
for payment-related subscription status changes.Sends notifications via the
Notification Service
.
Interaction Flow for Subscription Cancellation
CureFit calls the
Subscription Service
to cancel a subscription.The
Subscription Service
:Validates the subscription status.
Cancels the recurring payment schedule.
Updates the subscription status.
Sends a cancellation notification via the
Notification Service
.
3. Detailed Microservice Responsibilities
1. User Service
Responsibilities:
Manage user profiles (CRUD operations).
Validate users during subscription creation.
APIs:
POST /users
GET /users/{user_id}
PUT /users/{user_id}
2. Plan Service
Responsibilities:
Manage subscription plans (CRUD operations).
Retrieve plan details for validation during subscription creation.
APIs:
POST /plans
GET /plans/{plan_id}
PUT /plans/{plan_id}
3. Subscription Service
Responsibilities:
Manage subscriptions (CRUD operations).
Schedule recurring payments.
Update subscription status based on payments.
APIs:
POST /subscriptions
GET /subscriptions/{subscription_id}
PUT /subscriptions/{subscription_id}
DELETE /subscriptions/{subscription_id}
Integration:
Calls
User Service
to validate users.Calls
Plan Service
to validate plans.Calls
Payment Service
to process payments.
4. Payment Service
Responsibilities:
Process payments via Razorpay.
Retry failed payments.
Tokenize payment methods for recurring payments.
APIs:
POST /payments
GET /payments/{payment_id}
POST /payments/{payment_id}/retry
Integration:
Interacts with Razorpay for payment processing.
Updates
Subscription Service
with payment statuses.
5. Notification Service
Responsibilities:
Send notifications (e.g., payment success, failure, subscription updates).
Manage notification templates and delivery statuses.
APIs:
POST /notifications
GET /notifications/{notification_id}
Integration:
Subscribed to events from
Payment Service
andSubscription Service
.
6. Webhook Service
Responsibilities:
Handle Razorpay webhook events.
Forward events to appropriate services (
Payment Service
,Subscription Service
).
APIs:
POST /webhooks
Integration:
Receives webhook events from Razorpay.
Updates
Payment Service
andSubscription Service
.
7. Audit Service
Responsibilities:
Log all updates to subscriptions, plans, and payments for auditing.
APIs:
POST /audit-logs
GET /audit-logs/{entity_type}/{entity_id}
Integration:
Subscribed to events from
Subscription Service
andPayment Service
.
8. Reporting Service
Responsibilities:
Provide subscription and payment reports.
Enable analytics for CureFit.
APIs:
GET /reports/subscriptions
GET /reports/payments
Integration:
Queries
Subscription Service
andPayment Service
.
4. Event-Driven Architecture
To ensure asynchronous communication between microservices:
Use a Message Broker like Kafka or RabbitMQ.
Event Topics:
subscription_created
: Published by theSubscription Service
.payment_processed
: Published by thePayment Service
.webhook_received
: Published by theWebhook Service
.
5. High-Level Sequence Diagram
Subscription Creation:
CureFit → Subscription Service → User Service (Validate User)
CureFit → Subscription Service → Plan Service (Validate Plan)
Subscription Service → Payment Service → Razorpay (First Payment)
Recurring Payment:
Subscription Service → Payment Service → Razorpay (Recurring Payment)
Webhook Event:
Razorpay → Webhook Service → Payment Service → Subscription Service
Notifications:
Payment Service → Notification Service → CureFit/User
HLD
10% of users will subscribe to the service (100,000 subscriptions).
10M Users --> 1M subscription's