Subscriptions
SubscriptionProvider adds recurring billing: plans (a recurring price) and
subscriptions that charge a customer's stored payment method each billing
cycle. It's an optional capability implemented by Stripe and Razorpay;
PayPal returns payment.ErrUnsupported.
Subscriptions charge a saved off-session payment method, so on Stripe they build on the setup-intent flow.
Creating a plan
plan, err := client.CreatePlan(ctx, payment.NewPlanRequest(payment.USD(1999), payment.BillingIntervalMonth).
WithName("Pro").
WithIntervalCount(1))
Interval is BillingIntervalDay, Week, Month, or Year.
IntervalCount is the number of intervals between charges — Month + count
3 is quarterly — and defaults to 1. In Stripe, a plan becomes a recurring
Price; plan.ID is what you subscribe customers to.
Subscribing a customer
sub, err := client.CreateSubscription(ctx, payment.NewSubscriptionRequest(customerID, plan.ID).
WithPaymentMethod(paymentMethodID).
WithTrialDays(14))
if sub.IsActive() {
// sub.CurrentPeriodEnd is the next charge date
}
Subscription.Status is one of SubscriptionStatusActive, Trialing,
PastDue, Canceled, Incomplete, IncompleteExpired, Unpaid, or
Completed (a finite subscription that ran all its billing cycles — see
below).
Canceling
// Keep access until the current period ends
sub, err = client.CancelSubscription(ctx, sub.ID, &payment.CancelOptions{AtPeriodEnd: true})
// Cancel immediately
sub, err = client.CancelSubscription(ctx, sub.ID, nil)
A nil *CancelOptions cancels immediately.
Razorpay's mandate-authorization flow
Razorpay's subscription model differs from Stripe's in ways your code needs to branch on if you support both:
- A finite cycle count is required. Razorpay has no concept of
open-ended billing — set
SubscriptionRequest.TotalCountviaWithTotalCount. Stripe ignoresTotalCountentirely. - The customer authorizes the mandate via a redirect. Razorpay's
CreateSubscriptiondoes not acceptCustomerIDorPaymentMethodIDon the request — instead, the returnedSubscription.AuthURLis a customer-facing URL the customer must visit to authorize the recurring mandate. Until they do,StatusisSubscriptionStatusIncomplete. Once authorization completes, Razorpay populates the subscription'sCustomerIDfor you.AuthURLis empty for Stripe, which charges a pre-authorized payment method directly.
sub, err := client.CreateSubscription(ctx, payment.NewSubscriptionRequest("", plan.ID).
WithTotalCount(12)) // Razorpay: required; Stripe: ignored
if err != nil {
log.Fatal(err)
}
if sub.AuthURL != "" {
// redirect the customer to sub.AuthURL to authorize the mandate
}
Reacting to billing outcomes
Recurring charges surface as normalized webhook events rather than as polling — see Webhooks:
WebhookInvoicePaymentSucceeded— a recurring charge was paid (SubscriptionID,InvoiceID,Amountpopulated)WebhookInvoicePaymentFailed— a recurring charge failedWebhookSubscriptionCanceled— the subscription ended
Next steps
Each successful billing cycle produces an Invoice you can
retrieve with client.GetInvoice.