Back to portfolio
Case studyRef. SUBSCRIPTIONS

Subscription & Payment Manager

A full-stack SaaS for running subscription businesses: customers, tiered plans, billing and Razorpay payments behind role-based access. I built it to go deep on the hardest parts of payments: webhook reliability, signature verification, and never applying a payment twice.

  • React
  • Node.js
  • Express
  • PostgreSQL
  • Razorpay
  • JWT

Particulars

Type
Independent project, open source
Role
Sole designer and full stack engineer
Payments
Razorpay, webhook-driven
Scope
Auth, RBAC, subscriptions, billing and payments
Exhibit A: Subscriptions

01The mandate

Taking a payment is easy. Keeping subscription state correct when payment events arrive late, twice or out of order is not. I wanted a project where that problem was the point, wrapped in a product with real roles, plans and billing around it.

02What I owned

All of it. I designed role-based access for multiple user types, implemented authentication and protected workflows, built tier-based subscription and billing flows, and integrated Razorpay with webhook-driven payment updates.

I designed the backend APIs across authentication, users, subscriptions and payments, built the subscription management UI, added caching for frequently read data, and refactored modules as the system grew.

03Webhooks as the source of truth

The browser can say a checkout finished; only Razorpay can say a payment was captured. Subscription state changes on verified webhook events: each signature is checked against the shared secret, and processing is idempotent, so a retried or duplicated event can never apply twice.

Fig. 01

Client
React dashboardRazorpay checkout
API
Express + JWTRBAC middleware
Payments
RazorpaySigned webhooks
Data
PostgreSQLCache
Fig. 01 Architecture: subscription state is driven by verified, idempotent webhooks

04Working flow

The full path of a subscription payment. The client starts checkout, but only a verified webhook can change what a customer has paid for.

Fig. 02

Customer
React app
Express API
Razorpay
PostgreSQL
  1. 01 Chooses a plan

  2. 02 Requests an order (JWT)

  3. 03 Creates the order for the plan amount

  4. 04 Order ID

  5. 05 Order ID

  6. 06 Opens checkout; the customer pays

  7. 07 Signed webhook event

  8. 08 Verifies the signature, checks the event isn't already applied
  9. 09 Records the payment once, activates the subscription

  10. 10 Refreshes subscription status

  11. 11 Active plan and access

Fig. 02 Checkout, signed webhook, idempotent update

05Hard parts

  • Making duplicate and retried webhooks safe through idempotent processing.
  • Never trusting a payment event before verifying its signature.
  • Role-based access across multiple user types, enforced consistently in the API and the UI.
  • Caching frequently read data without serving stale subscription state.

06Outcomes

  • A working subscription platform covering plans, billing and payments end to end.
  • Payment processing that is verified and duplicate-safe by design.
  • Tier-based plans and billing workflows behind role-based access.

07How I approached it

  1. 01

    Trust the processor, verify the message

    Payment state comes from signed events, not the client.

  2. 02

    Design for retries

    Anything delivered over the network will eventually arrive twice.

  3. 03

    Permissions are architecture

    Roles were modelled up front, not patched in per screen.

  4. 04

    Refactor as it grows

    Modules were reshaped as the domain became clearer.

End of case study7 sections

Related work

More projects
Back to all projects