cashier

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package cashier is a multi-gateway billing plugin for Nimbus, modeled on Laravel Cashier but gateway-agnostic. One app can register several payment gateways (Stripe, Razorpay, PayU, …), pick a default, select a gateway per request, verify webhooks, and gate access with a paywall.

app.Use(cashier.NewPlugin(cashier.Config{
    FromEnv:  true,          // register gateways whose env keys are set
    Default:  "razorpay",    // default gateway
    OnWebhook: func(e cashier.WebhookEvent) error {
        switch events.Normalize(e) {
        case events.PaymentSucceeded:      // grant paywall access
        case events.SubscriptionCancelled: // revoke
        }
        return nil
    },
}))

Layout:

cashier.go   – plugin + facade      config.go   – Config
manager.go   – GatewayManager       paywall.go  – Paywall engine
routes.go    – webhook routes       contracts/  – PaymentGateway interface
gateways/    – Stripe/Razorpay/PayU  models/     – transactions, subscriptions
events/      – canonical events     views/      – checkout templates

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cashier

type Cashier struct {
	Gateways *GatewayManager
	Paywall  *Paywall
}

Cashier is the facade tying the gateway manager to the paywall. Resolve it from the container ("cashier") or hold the plugin's instance.

func (*Cashier) Charge

func (c *Cashier) Charge(ctx context.Context, gatewayName string, p ChargeParams) (*Charge, error)

Charge starts a payment on the named gateway (empty → the default gateway).

func (*Cashier) HasAccess

func (c *Cashier) HasAccess(subject, plan string) bool

HasAccess is a shortcut to the paywall check.

type Charge

type Charge = contracts.Charge

Re-exported contract types so callers use the cashier package without importing contracts directly.

type ChargeParams

type ChargeParams = contracts.ChargeParams

Re-exported contract types so callers use the cashier package without importing contracts directly.

type Config

type Config struct {
	// Manager is the gateway registry. Nil → a new empty one is created.
	Manager *GatewayManager
	// Default gateway name. Falls back to PAYMENTS_DEFAULT_GATEWAY, then the
	// first registered gateway.
	Default string
	// FromEnv auto-registers gateways whose credentials are present in the
	// environment (Stripe: STRIPE_KEY[/STRIPE_WEBHOOK_SECRET]; Razorpay:
	// RAZORPAY_KEY_ID/RAZORPAY_KEY_SECRET[/RAZORPAY_WEBHOOK_SECRET]; PayU:
	// PAYU_MERCHANT_KEY/PAYU_MERCHANT_SALT).
	FromEnv bool
	// Paywall backs entitlement checks (nil → in-memory store).
	Paywall *Paywall
	// WebhookPrefix mounts per-gateway webhooks at "<prefix>/<gateway>/webhook".
	// Default "/payments".
	WebhookPrefix string
	// OnWebhook runs for every verified webhook (any gateway). Use
	// events.Normalize(evt) to branch on canonical events and grant/revoke
	// paywall access.
	OnWebhook func(WebhookEvent) error
}

Config configures the Cashier plugin.

type Entitlement

type Entitlement struct {
	Subject   string
	Plan      string
	ExpiresAt time.Time
}

Entitlement grants a subject (usually a user id) access to a plan until ExpiresAt. A zero ExpiresAt means it never expires.

type EntitlementStore

type EntitlementStore interface {
	Grant(e Entitlement) error
	Revoke(subject, plan string) error
	Active(subject, plan string) (bool, error)
	List(subject string) ([]Entitlement, error)
}

EntitlementStore persists entitlements. Implement it to back the paywall with a database; MemoryEntitlementStore is the default in-memory implementation.

type Gateway

type Gateway = contracts.PaymentGateway

Re-exported contract types so callers use the cashier package without importing contracts directly.

type GatewayManager

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

GatewayManager holds the app's registered gateways and the default selection. It is safe for concurrent use — one app can serve many gateways at once and pick per request.

func NewGatewayManager

func NewGatewayManager() *GatewayManager

NewGatewayManager creates an empty gateway registry.

func (*GatewayManager) Default

func (m *GatewayManager) Default() Gateway

Default returns the default gateway, or nil when none are registered.

func (*GatewayManager) DefaultName

func (m *GatewayManager) DefaultName() string

DefaultName returns the default gateway's name.

func (*GatewayManager) Gateway

func (m *GatewayManager) Gateway(name string) (Gateway, error)

Gateway returns the gateway registered under name.

func (*GatewayManager) Names

func (m *GatewayManager) Names() []string

Names returns the registered gateway names, sorted.

func (*GatewayManager) Register

func (m *GatewayManager) Register(g Gateway) *GatewayManager

Register adds a gateway. The first one registered becomes the default until SetDefault is called. Re-registering the same name replaces it.

func (*GatewayManager) SetDefault

func (m *GatewayManager) SetDefault(name string) *GatewayManager

SetDefault selects the default gateway by name (no-op if not registered).

func (*GatewayManager) Use

func (m *GatewayManager) Use(name string) (Gateway, error)

Use resolves a gateway by name, falling back to the default when name is empty — the typical per-request selector.

type MemoryEntitlementStore

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

MemoryEntitlementStore is a concurrency-safe in-memory EntitlementStore. Use a database-backed store in production (entitlements should survive a restart).

func NewMemoryEntitlementStore

func NewMemoryEntitlementStore() *MemoryEntitlementStore

NewMemoryEntitlementStore creates an empty in-memory store.

func (*MemoryEntitlementStore) Active

func (s *MemoryEntitlementStore) Active(subject, plan string) (bool, error)

func (*MemoryEntitlementStore) Grant

func (*MemoryEntitlementStore) List

func (s *MemoryEntitlementStore) List(subject string) ([]Entitlement, error)

func (*MemoryEntitlementStore) Revoke

func (s *MemoryEntitlementStore) Revoke(subject, plan string) error

type PaymentProof

type PaymentProof = contracts.PaymentProof

Re-exported contract types so callers use the cashier package without importing contracts directly.

type Paywall

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

Paywall gates access to plans/features based on entitlements. Grant on a successful payment (typically in a webhook handler); gate routes with RequirePlan.

func NewPaywall

func NewPaywall(store EntitlementStore) *Paywall

NewPaywall builds a paywall over a store (nil → in-memory).

func (*Paywall) Grant

func (p *Paywall) Grant(subject, plan string, expires time.Time) error

Grant gives subject access to plan until expires (zero time = forever).

func (*Paywall) HasAccess

func (p *Paywall) HasAccess(subject, plan string) bool

HasAccess reports whether subject currently has active access to plan.

func (*Paywall) RequirePlan

func (p *Paywall) RequirePlan(plan string, subjectFn func(*nhttp.Context) string) router.Middleware

RequirePlan returns middleware that blocks a route unless the current subject has active access to plan. subjectFn extracts the subject (e.g. the user id) from the request; return "" for an anonymous/unknown user. Blocked requests receive HTTP 402 Payment Required.

func (*Paywall) Revoke

func (p *Paywall) Revoke(subject, plan string) error

Revoke removes a subject's access to a plan.

func (*Paywall) Store

func (p *Paywall) Store() EntitlementStore

Store returns the underlying store.

type Plugin

type Plugin struct {
	nimbus.BasePlugin
	Cashier *Cashier
	// contains filtered or unexported fields
}

Plugin wires Cashier into Nimbus.

func NewPlugin

func NewPlugin(cfg Config) *Plugin

NewPlugin builds the Cashier plugin from config.

func (*Plugin) Boot

func (p *Plugin) Boot(app *nimbus.App) error

func (*Plugin) DefaultConfig

func (p *Plugin) DefaultConfig() map[string]any

func (*Plugin) Migrations

func (p *Plugin) Migrations() []database.Migration

Migrations creates the cashier tables (transactions, subscriptions).

func (*Plugin) Register

func (p *Plugin) Register(app *nimbus.App) error

func (*Plugin) RegisterRoutes

func (p *Plugin) RegisterRoutes(r *router.Router)

RegisterRoutes mounts a signature-verified webhook endpoint per gateway at "<WebhookPrefix>/<gateway>/webhook" (e.g. /payments/razorpay/webhook).

type WebhookEvent

type WebhookEvent = contracts.WebhookEvent

Re-exported contract types so callers use the cashier package without importing contracts directly.

Directories

Path Synopsis
Package contracts defines the payment-gateway contract and the shared value types every gateway and the manager operate on.
Package contracts defines the payment-gateway contract and the shared value types every gateway and the manager operate on.
Package events defines canonical, gateway-agnostic payment events and maps each gateway's raw webhook types onto them — so paywall logic (grant/revoke) is written once regardless of which gateway delivered the event.
Package events defines canonical, gateway-agnostic payment events and maps each gateway's raw webhook types onto them — so paywall logic (grant/revoke) is written once regardless of which gateway delivered the event.
Package gateways holds the concrete payment gateways (Stripe, Razorpay, PayU, …).
Package gateways holds the concrete payment gateways (Stripe, Razorpay, PayU, …).
Package models holds the persisted Cashier tables (transactions, subscriptions) and their migrations.
Package models holds the persisted Cashier tables (transactions, subscriptions) and their migrations.

Jump to

Keyboard shortcuts

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