A subscription store is not simply a normal checkout with a “repeat every month” option.
It is a stateful system connecting customer consent, plans, payments, recurring orders, inventory, shipping, notifications, refunds, and customer-service actions. The most difficult work lives in the transitions between those areas.
This article explains the architecture questions behind a custom Medusa.js subscription platform using Indian payment gateways and shipping workflows. It reflects lessons from our Puritas Medusa.js implementation without exposing confidential code or merchant configuration.
The central design principle: model the subscription, payment, order, and fulfilment as related but separate states. Do not treat a gateway callback as the complete business process.
Start with the subscription contract
Before writing a payment module, define what the customer is agreeing to.
Questions include:
- Is the plan prepaid, recurring, or manually renewed?
- Is the price fixed or recalculated each cycle?
- Can products or quantities change?
- Can a customer skip, pause, resume, or cancel?
- When does a change take effect?
- What happens to promotions after the first order?
- How are taxes and shipping recalculated?
- What happens when a product becomes unavailable?
These decisions become the subscription data model and workflow rules.
Keep four state machines separate
1. Subscription state
Examples: pending, active, paused, cancellation-scheduled, cancelled, expired.
2. Payment state
Examples: session-created, pending, authorised, captured, failed, refunded.
3. Order state
Examples: draft, awaiting-payment, confirmed, cancelled, completed.
4. Fulfilment state
Examples: not-ready, ready-to-ship, booked, shipped, delivered, returned.
If these are collapsed into one status, exception handling becomes unpredictable. A payment may succeed while shipping booking fails. A subscription may remain active while one cycle is paused. An order may be refunded without cancelling future subscription cycles.
The role of a Medusa payment module
Medusa’s framework provides payment interfaces and workflows that an integration can implement for a provider. A production module usually needs to handle:
- Creating or updating a payment session
- Sending the correct amount and merchant reference
- Redirect or app-switch behaviour where required
- Verifying signed callbacks or webhooks
- Reconciling asynchronous events
- Authorisation, capture, cancellation, and refunds where supported
- Translating provider states into platform states
- Idempotency and duplicate-event protection
- Operational logging without exposing secrets
The Medusa documentation explains how commerce modules and workflows can be extended around custom requirements.
Razorpay and PhonePe are not interchangeable
Both can participate in an Indian ecommerce payment architecture, but the available products, checkout experiences, recurring-payment capabilities, settlement behaviour, and merchant-account requirements can differ.
The integration should therefore expose a stable commerce interface while keeping provider-specific behaviour inside the module.
Do not assume that because one gateway supports a workflow in a dashboard, the same workflow is available through the merchant’s enabled API product. Confirm the commercial account, API documentation, test environment, and production approvals early.
Webhooks must be treated as untrusted, repeatable input
Payment webhooks can arrive late, more than once, or out of order. A secure handler should:
- Verify the provider signature.
- Reject unsupported event types.
- Store or derive an idempotency key.
- Check the current payment and order state.
- Apply only valid transitions.
- Record enough context for reconciliation.
- Return promptly and continue non-critical work asynchronously.
Never mark an order paid only because the browser returned to a “success” URL. Confirm the result using the trusted provider event or server-side verification method.
Generating recurring orders
A subscription renewal is usually best handled by an explicit workflow:
- Find subscriptions due for a cycle.
- Lock or mark the cycle to prevent duplicate processing.
- Validate customer, address, plan, products, price, and inventory.
- Create a draft or pending order.
- initiate the appropriate payment action.
- Confirm the order after verified payment state.
- Begin fulfilment preparation.
- Notify the customer.
- Record the next cycle date or exception.
Medusa workflows are useful here because they organise multi-step operations and can support compensating actions when a later step fails.
Shipping has its own cycle
The shipping module needs more than a rate lookup.
For subscription commerce, consider:
- Whether serviceability is rechecked each cycle
- Address changes between billing and fulfilment
- Weight or package changes
- Carrier rate changes
- Inventory split across locations
- Shipment creation and label generation
- Tracking updates
- Delivery failure and return-to-origin
- Skipped or paused cycles
- Shipping refunds
Billing the customer before validating fulfilment can create avoidable refunds. Reserving inventory too early can block stock unnecessarily. The correct sequence depends on product shelf life, stock policy, provider behaviour, and fulfilment operations.
Customer controls and support tools
A good subscription system needs clear customer actions:
- View plan and next date
- Pause or resume
- Skip a cycle
- Change address
- Change an allowed product or quantity
- Update the payment method where supported
- Cancel with clear effective timing
- View related orders and payment history
Support teams also need safe administrative actions and an audit trail. Manual database edits are not an operating model.
Observability is part of the feature
Track:
- Renewals due and processed
- Payment success and failure by provider
- Duplicate or rejected events
- Orders awaiting manual review
- Shipping booking failures
- Subscription churn reasons
- Refund and return patterns
Alerts should focus on conditions requiring action, not every normal event.
Production checklist
- Test duplicate and out-of-order webhooks.
- Test payment success with order or shipping failure.
- Test refunds and cancellations at different stages.
- Test expired or invalid addresses.
- Test plan changes near a billing boundary.
- Test inventory shortages.
- Test gateway and carrier timeouts.
- Confirm secret rotation and restricted log access.
- Document reconciliation and incident procedures.
Our Medusa.js development service covers architecture, custom modules, storefronts, integrations, migration, and ongoing engineering for commerce models that require this degree of control.
