billing

package
v0.0.0-...-4a3d204 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package billing wraps the slice of the Razorpay API the managed cloud needs: creating subscriptions, verifying the client-side checkout payment signature, cancelling subscriptions, and verifying inbound webhook signatures. It talks to Razorpay over plain HTTP so the project takes on no third-party SDK dependency, and it degrades to a clean no-op when no API keys are configured (self-hosted / OSS).

Index

Constants

This section is empty.

Variables

View Source
var ErrNoPlan = errors.New("no plan configured for tier")

ErrNoPlan is returned when the requested plan has no configured Razorpay plan id.

View Source
var ErrNotConfigured = errors.New("billing not configured")

ErrNotConfigured is returned by subscription/cancel calls when Razorpay is disabled.

View Source
var ErrPlanChangeUnsupported = errors.New("plan change not supported for this payment method")

ErrPlanChangeUnsupported is returned when Razorpay refuses an in-place plan change because the subscription's payment method (UPI/eMandate) can't be updated.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a minimal Razorpay REST client.

func New

func New(keyID, keySecret, webhookSecret string, planIDs map[string]string) *Client

New builds a Razorpay client. planIDs is keyed by plan tier name (developer/team/growth). When keyID or keySecret is empty the client reports Enabled() == false and all calls no-op.

func (*Client) CancelSubscription

func (c *Client) CancelSubscription(ctx context.Context, subscriptionID string, atCycleEnd bool) error

CancelSubscription cancels a Razorpay subscription. When atCycleEnd is true the subscription stays active until the end of the current billing cycle (the org keeps the access it paid for); the downgrade to free arrives via the subscription.cancelled webhook.

func (*Client) CreateSubscription

func (c *Client) CreateSubscription(ctx context.Context, p SubscribeParams) (string, error)

CreateSubscription creates a Razorpay subscription in the "created" state and returns its id. The browser then opens the Checkout modal with this id + the public key to collect payment.

func (*Client) Enabled

func (c *Client) Enabled() bool

Enabled reports whether Razorpay API credentials are configured.

func (*Client) HasPlan

func (c *Client) HasPlan(plan domain.Plan) bool

HasPlan reports whether a self-serve Razorpay plan is configured for the tier.

func (*Client) KeyID

func (c *Client) KeyID() string

KeyID returns the public Razorpay key id, safe to hand to the browser to open the Checkout modal.

func (*Client) PlanForPlanID

func (c *Client) PlanForPlanID(planID string) (domain.Plan, bool)

PlanForPlanID reverse-maps a Razorpay plan id to a plan tier. Returns ("", false) when the plan id is unknown.

func (*Client) UpdateSubscriptionPlan

func (c *Client) UpdateSubscriptionPlan(ctx context.Context, subscriptionID string, plan domain.Plan, atCycleEnd bool) error

UpdateSubscriptionPlan changes the plan on an existing subscription in place. When atCycleEnd is true the change applies at the end of the current billing cycle (downgrades — the org keeps what it already paid for); otherwise it applies immediately (upgrades). Razorpay only permits this for card mandates; UPI/eMandate subscriptions return ErrPlanChangeUnsupported.

func (*Client) VerifyAndParse

func (c *Client) VerifyAndParse(payload []byte, sigHeader string) (*Event, error)

VerifyAndParse checks the X-Razorpay-Signature header against the configured webhook secret, then decodes the event. It fails closed: without a configured webhook secret the event cannot be authenticated, so it is rejected rather than processed — otherwise anyone could POST forged subscription events (the webhook route is public) to grant themselves a paid plan or cancel a victim's.

func (*Client) VerifyPaymentSignature

func (c *Client) VerifyPaymentSignature(paymentID, subscriptionID, signature string) bool

VerifyPaymentSignature checks the signature returned by the Checkout modal's success handler. For subscriptions Razorpay signs "<payment_id>|<subscription_id>" with the key secret (note the order differs from one-off orders). Returns true when the signature is valid.

type Event

type Event struct {
	Type           string // e.g. subscription.activated, subscription.charged
	TenantID       string // from the subscription's notes[tenant_id]
	CustomerID     string
	SubscriptionID string
	Status         string // subscription status (active, pending, halted, cancelled, ...)
	PlanID         string
}

Event is the decoded slice of a Razorpay webhook we act on, flattened from the subscription entity carried by subscription.* events.

type SubscribeParams

type SubscribeParams struct {
	Plan          domain.Plan
	TenantID      string // stored in notes[tenant_id], echoed back on webhooks
	CustomerEmail string // pre-fills the customer's email on Razorpay notifications
}

SubscribeParams configures a subscription created for the embedded Checkout modal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL