Skip to main content

Partner Subscription Module

The partner-plan module manages subscription plans, active subscriptions, and payment tracking for partners.

Module Structure

src/modules/partner-plan/
├── index.ts # Module export (PARTNER_PLAN_MODULE = "partnerPlan")
├── service.ts # MedusaService({ PartnerPlan, PartnerSubscription, SubscriptionPayment })
├── types/index.ts # Enums
├── models/
│ ├── partner-plan.ts # Plan definitions
│ ├── partner-subscription.ts # Active subscriptions
│ └── subscription-payment.ts # Payment records
└── migrations/
├── Migration20260317040742.ts # Initial tables
└── Migration20260317165831.ts # Added payment_provider + payments

Data Models

PartnerPlan

FieldTypeDefaultDescription
idtext (PK)auto
nametext (searchable)Plan name
slugtext (unique)URL-safe identifier
descriptiontext (nullable)Plan description
pricefloat0Price in currency units
currency_codetext"inr"ISO currency
intervalenum"monthly"monthly / yearly
featuresjson (nullable)Feature flags object
is_activebooleantrueAvailable for selection
sort_ordernumber0Display order
subscriptionshasMany→ PartnerSubscription

PartnerSubscription

FieldTypeDefaultDescription
idtext (PK)auto
partner_idtextPartner ID
statusenum"active"active / canceled / expired / past_due
payment_providerenum"manual"payu / stripe / manual
current_period_startdatetimeBilling period start
current_period_enddatetime (nullable)Billing period end
canceled_atdatetime (nullable)When canceled
planbelongsTo→ PartnerPlan
paymentshasMany→ SubscriptionPayment

SubscriptionPayment

FieldTypeDefaultDescription
idtext (PK)auto
amountfloatPayment amount
currency_codetext"inr"Currency
statusenum"pending"pending / processing / completed / failed / refunded
providerenum"manual"payu / stripe / manual
provider_reference_idtext (nullable)External payment ID
provider_datajson (nullable)Full provider response
period_startdatetimeWhat billing period this covers
period_enddatetime
paid_atdatetime (nullable)When payment succeeded
failed_atdatetime (nullable)When payment failed
failure_reasontext (nullable)Error message
subscriptionbelongsTo→ PartnerSubscription

Enums

enum PlanInterval { MONTHLY = "monthly", YEARLY = "yearly" }
enum SubscriptionStatus { ACTIVE, CANCELED, EXPIRED, PAST_DUE }
enum PaymentProvider { PAYU = "payu", STRIPE = "stripe", MANUAL = "manual" }
enum SubscriptionPaymentStatus { PENDING, PROCESSING, COMPLETED, FAILED, REFUNDED }

src/links/partner-subscription.ts — links Partner (1) ↔ PartnerSubscription (many)

Workflows

create-subscription

src/workflows/partner-subscription/create-subscription.ts

  1. Cancels any existing active subscriptions for the partner
  2. Creates new subscription with plan, status, period, payment_provider
  3. Links subscription to partner via remoteLink

cancel-subscription

src/workflows/partner-subscription/cancel-subscription.ts

Sets status to canceled with timestamp. Compensation restores previous state.

seed-plans

src/workflows/partner-subscription/seed-plans.ts

Idempotent — creates Simple/Pro/Max if not present. Also available as:

npx medusa exec src/scripts/seed-partner-plans.ts

Scheduled Job

src/jobs/check-subscription-expiry.ts — runs daily at midnight:

  1. Free plans: auto-renew + record $0 payment
  2. Paid plans expired: mark past_due + create pending payment record
  3. Past due > 7 days: mark expired

Subscriber

src/subscribers/partner-assign-free-plan.ts — listens for partner.created.fromAdmin event and auto-assigns the Simple (free) plan to new partners.

Payment Provider Selection

Determined by partner's currency:

  • metadata.currency_code === "inr" → PayU
  • Otherwise → Stripe
  • Admin can override via the payment_provider field