Documentation
¶
Overview ¶
Package stripeflow provides a pluggable Go library for integrating Stripe subscriptions into your application. It focuses on billing portal access, webhook processing, subscription state management, and product catalogue syncing — with support for PostgreSQL, MySQL, and SQLite.
Quick start:
sf, err := stripeflow.New(stripeflow.Config{
Dialect: stripeflow.Postgres,
DB: db,
StripeSecretKey: "sk_live_...",
WebhookSecret: "whsec_...",
GetUserID: func(r *http.Request) (string, error) {
return sessionUserID(r), nil
},
})
// Register webhook handler
http.Handle("/stripe/webhook", sf.WebhookHandler())
// Protect routes
http.Handle("/app/", sf.RequireActiveOrTrial(appHandler))
Index ¶
- Variables
- func Int64Ptr(v int64) *int64
- type CheckoutParams
- type Client
- func (c *Client) ArchivePrice(ctx context.Context, priceID string) error
- func (c *Client) CreateCheckoutSession(ctx context.Context, p CheckoutParams) (string, error)
- func (c *Client) CreatePortalSession(ctx context.Context, p PortalParams) (string, error)
- func (c *Client) CreatePrice(ctx context.Context, p CreatePriceParams) (*Price, error)
- func (c *Client) CreateProduct(ctx context.Context, p CreateProductParams) (*Product, error)
- func (c *Client) DeleteAllProducts(ctx context.Context) error
- func (c *Client) DeleteProduct(ctx context.Context, productID string) error
- func (c *Client) GetProductByID(ctx context.Context, id string) (*Product, error)
- func (c *Client) GetSubscription(ctx context.Context, userID string) (*Subscription, error)
- func (c *Client) GetSubscriptionByCustomerID(ctx context.Context, customerID string) (*Subscription, error)
- func (c *Client) GetSubscriptionByID(ctx context.Context, id int64) (*Subscription, error)
- func (c *Client) GetSubscriptionByStripeSubID(ctx context.Context, subID string) (*Subscription, error)
- func (c *Client) Handler() http.Handler
- func (c *Client) IncrementUsage(ctx context.Context, userID string, delta int64) (int64, error)
- func (c *Client) ListPrices(ctx context.Context, productID string) ([]Price, error)
- func (c *Client) ListProducts(ctx context.Context, activeOnly bool) ([]Product, error)
- func (c *Client) ProvisionProduct(ctx context.Context, params ProvisionParams) (*ProvisionResult, error)
- func (c *Client) ProvisionProductsFromJSON(ctx context.Context, data []byte) ([]ProvisionResult, error)
- func (c *Client) ReportMeterEvent(ctx context.Context, stripeCustomerID string, eventName string, value int64) error
- func (c *Client) RequireActiveOrTrial(next http.Handler) http.Handler
- func (c *Client) RequireActiveSubscription(next http.Handler) http.Handler
- func (c *Client) RequireSubscription(next http.Handler, opts ...MiddlewareOptions) http.Handler
- func (c *Client) ResetUsage(ctx context.Context, userID string) error
- func (c *Client) SetUsageLimit(ctx context.Context, userID string, limit *int64) error
- func (c *Client) SyncProducts(ctx context.Context) (*SyncResult, error)
- func (c *Client) UpdateProduct(ctx context.Context, p UpdateProductParams) (*Product, error)
- func (c *Client) WebhookHandler() http.Handler
- type Config
- type CreatePriceParams
- type CreateProductParams
- type DeniedFunc
- type Dialect
- type MiddlewareOptions
- type PortalParams
- type Price
- type PriceInterval
- type Product
- type ProvisionFeature
- type ProvisionParams
- type ProvisionPriceInfo
- type ProvisionPriceParams
- type ProvisionProductParams
- type ProvisionRecurringParams
- type ProvisionResult
- type ProvisionTransformQtyParams
- type RecurringParams
- type Subscription
- type SubscriptionStatus
- type SyncResult
- type UpdateProductParams
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoSubscription = errors.New("stripeflow: no subscription found") ErrSubscriptionInactive = errors.New("stripeflow: subscription is not active") ErrUsageLimitReached = errors.New("stripeflow: usage limit reached") ErrTrialExpired = errors.New("stripeflow: trial has expired") )
Sentinel errors returned by middleware and programmatic helpers.
Functions ¶
Types ¶
type CheckoutParams ¶
type CheckoutParams struct {
UserID string
PriceID string
SuccessURL string
CancelURL string
TrialDays *int64
Metadata map[string]string
}
CheckoutParams holds options for creating a Stripe Checkout session.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the main stripeflow object. Create one via New().
func New ¶
New creates and initialises a stripeflow Client. The Stripe API key is set globally at initialisation time.
func (*Client) ArchivePrice ¶
ArchivePrice marks a price as inactive in Stripe (prices cannot be deleted).
func (*Client) CreateCheckoutSession ¶ added in v0.0.11
CreateCheckoutSession creates a Stripe Checkout session to subscribe a user to a specific price. Returns the checkout URL to redirect the user to.
func (*Client) CreatePortalSession ¶
CreatePortalSession creates a Stripe Billing Portal session so the user can manage their subscription, update payment methods, and download invoices. Returns the portal URL to redirect the user to.
func (*Client) CreatePrice ¶
CreatePrice creates a price in Stripe and stores it locally. Calling it again for the same product with the same currency/amount/interval reuses the existing Stripe price instead of creating a duplicate.
func (*Client) CreateProduct ¶
CreateProduct creates a product in Stripe and stores it locally. Calling it again with the same Name reuses the existing Stripe product instead of creating a duplicate.
func (*Client) DeleteAllProducts ¶ added in v0.0.7
DeleteAllProducts deletes all products and prices from the local database and attempts to archive them in Stripe.
func (*Client) DeleteProduct ¶ added in v0.0.7
DeleteProduct deletes a product and all of its associated prices from the local database. In Stripe, prices are archived, and the product itself is archived (made inactive) because Stripe does not allow deleting products that have ever had prices.
func (*Client) GetProductByID ¶ added in v0.0.6
GetProductByID retrieves a product by its ID.
func (*Client) GetSubscription ¶
GetSubscription retrieves the current subscription state for a user.
func (*Client) GetSubscriptionByCustomerID ¶ added in v0.0.6
func (c *Client) GetSubscriptionByCustomerID(ctx context.Context, customerID string) (*Subscription, error)
GetSubscriptionByCustomerID retrieves a subscription by Stripe Customer ID.
func (*Client) GetSubscriptionByID ¶ added in v0.0.6
GetSubscriptionByID retrieves a subscription by its primary key ID.
func (*Client) GetSubscriptionByStripeSubID ¶ added in v0.0.6
func (c *Client) GetSubscriptionByStripeSubID(ctx context.Context, subID string) (*Subscription, error)
GetSubscriptionByStripeSubID retrieves a subscription by Stripe Subscription ID.
func (*Client) Handler ¶
Handler returns an http.Handler that mounts the checkout, portal and webhook routes. For full control over routing, call CreateCheckoutSession, CreatePortalSession and WebhookHandler directly instead.
POST /checkout — creates a Checkout session, redirects to Stripe GET /portal — creates a Billing Portal session, redirects to Stripe POST /webhook — receives and processes Stripe webhook events
func (*Client) IncrementUsage ¶
IncrementUsage adds delta to the user's usage counter and returns the new total. Typically called after a successful API operation.
newCount, err := sf.IncrementUsage(ctx, userID, 1)
func (*Client) ListPrices ¶
ListPrices returns locally cached prices for a product.
func (*Client) ListProducts ¶
ListProducts returns locally cached products.
func (*Client) ProvisionProduct ¶ added in v0.0.3
func (c *Client) ProvisionProduct(ctx context.Context, params ProvisionParams) (*ProvisionResult, error)
ProvisionProduct creates a product and all its associated prices in Stripe, syncing each resource to the local database. The operation is sequential: the product is created first, then each price is created in order.
If any price creation fails, the product and any previously created prices will remain in Stripe — check your Stripe dashboard to clean up.
func (*Client) ProvisionProductsFromJSON ¶ added in v0.0.10
func (c *Client) ProvisionProductsFromJSON(ctx context.Context, data []byte) ([]ProvisionResult, error)
ProvisionProductsFromJSON is a convenience wrapper that unmarshals a JSON array of ProvisionParams and calls ProvisionProduct for each.
raw, _ := os.ReadFile("products.json")
results, err := client.ProvisionProductsFromJSON(ctx, raw)
func (*Client) ReportMeterEvent ¶ added in v0.0.5
func (c *Client) ReportMeterEvent(ctx context.Context, stripeCustomerID string, eventName string, value int64) error
ReportMeterEvent pushes a high-throughput usage event to Stripe's Billing v2 engine. The eventName must match the EventName of a Stripe Meter.
err := sf.ReportMeterEvent(ctx, stripeCustomerID, "api_check", 1)
func (*Client) RequireActiveOrTrial ¶
RequireActiveOrTrial allows users who are actively subscribed OR in a valid trial.
func (*Client) RequireActiveSubscription ¶
RequireActiveSubscription requires a fully paid (non-trial) active subscription.
func (*Client) RequireSubscription ¶
RequireSubscription is an http.Handler middleware that rejects requests from users without an active subscription (or valid trial, depending on options).
The resolved *Subscription is stored in the context and accessible via SubscriptionFromContext. Config.GetUserID must be set.
mux.Handle("/app/", sf.RequireSubscription(appHandler))
mux.Handle("/api/", sf.RequireSubscription(apiHandler, stripeflow.MiddlewareOptions{
AllowTrialing: false,
CheckUsageLimit: true,
}))
func (*Client) ResetUsage ¶
ResetUsage zeroes the usage counter for a user. Typically called at the start of each billing period.
func (*Client) SetUsageLimit ¶
SetUsageLimit sets or removes the usage cap for a user. Pass nil to remove the limit (unlimited).
err := sf.SetUsageLimit(ctx, userID, stripeflow.Int64Ptr(1000))
func (*Client) SyncProducts ¶
func (c *Client) SyncProducts(ctx context.Context) (*SyncResult, error)
SyncProducts fetches all products and their prices from Stripe and upserts them into the local database. Call this on startup or via a cron job.
func (*Client) UpdateProduct ¶
UpdateProduct updates a product in Stripe and refreshes the local copy.
func (*Client) WebhookHandler ¶
WebhookHandler returns an http.Handler that verifies and processes Stripe webhook events. Mount it at the endpoint configured in the Stripe dashboard.
http.Handle("/stripe/webhook", sf.WebhookHandler())
type Config ¶
type Config struct {
// Dialect specifies the SQL dialect (Postgres, MySQL, SQLite).
Dialect Dialect
// DB is the *sql.DB connection to use. stripeflow manages its own tables
// under the "stripeflow_" namespace.
DB *sql.DB
// StripeSecretKey is your Stripe secret API key (sk_live_... or sk_test_...).
StripeSecretKey string
// WebhookSecret is the signing secret for your Stripe webhook endpoint (whsec_...).
WebhookSecret string
// GetUserID extracts the authenticated user's identifier from an HTTP request.
// Required when using any middleware. Typically reads a JWT or session cookie.
GetUserID func(r *http.Request) (string, error)
// OnEvent is an optional hook called after every successfully processed webhook
// event. Useful for cache invalidation, audit logging, etc.
OnEvent func(event *stripe.Event)
// TrialDays sets the default number of free trial days for new subscriptions.
// Can be overridden per-checkout via CheckoutParams.TrialDays. Zero = no trial.
TrialDays int64
// UsageLimitEnabled toggles the built-in usage-limit check globally.
// When true, middleware will deny requests once usage_count >= usage_limit.
UsageLimitEnabled bool
}
Config holds all configuration needed to initialise a StripeFlow client.
type CreatePriceParams ¶
type CreatePriceParams struct {
// StripeProductID is the parent product (prod_...).
StripeProductID string
// UnitAmount is in the smallest currency unit (e.g. cents for USD).
UnitAmount int64
// Currency is a 3-letter ISO code, e.g. "usd".
Currency string
// Recurring – if nil, a one-time price is created.
Recurring *RecurringParams
Metadata map[string]string
}
CreatePriceParams defines a new recurring or one-time price.
type CreateProductParams ¶
type CreateProductParams struct {
Name string
Description string
// Images are URLs to product images.
Images []string
Metadata map[string]string
}
CreateProductParams defines a new product to create in Stripe (and sync locally).
type DeniedFunc ¶
type DeniedFunc func(w http.ResponseWriter, r *http.Request, reason error)
DeniedFunc is called by middleware when access is denied. It should write an appropriate HTTP response and return. If nil in MiddlewareOptions, a default JSON response is used.
type MiddlewareOptions ¶
type MiddlewareOptions struct {
// OnDenied overrides the default HTTP response when access is denied.
// If nil, a default JSON error response is used.
OnDenied DeniedFunc
// AllowTrialing permits requests from users in a valid (non-expired) trial.
// Defaults to true when using RequireActiveOrTrial.
AllowTrialing bool
// CheckUsageLimit enables the usage-limit check for this specific route,
// regardless of the global Config.UsageLimitEnabled setting.
CheckUsageLimit bool
}
MiddlewareOptions customises the behaviour of subscription middleware.
type PortalParams ¶
type PortalParams struct {
// UserID is your internal user identifier.
UserID string
// ReturnURL is where the customer lands after leaving the portal.
ReturnURL string
}
PortalParams holds options for creating a Billing Portal session.
type Price ¶
type Price struct {
ID string
ProductID string
Currency string
UnitAmount *int64
RecurringInterval string
RecurringCount *int
// UsageType is "licensed" for flat-rate subscription prices and "metered"
// for per-unit prices billed via meter events. Empty for one-time prices.
UsageType string
// Type is "recurring" or "one_time".
Type string
// Nickname is an optional human-readable label set in Stripe (e.g. "Starter — monthly").
Nickname string
// LookupKey is an optional stable string key assigned in Stripe that lets
// you reference this price without hardcoding its ID.
LookupKey string
Active bool
Metadata *json.RawMessage
StripeCreatedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
Price mirrors a Stripe price stored locally.
func (*Price) IsMetered ¶ added in v0.0.12
IsMetered reports whether this is a metered/per-unit price (as opposed to a flat-rate licensed subscription price).
func (*Price) IsRecurring ¶ added in v0.0.12
IsRecurring reports whether this is a recurring (subscription) price as opposed to a one-time price.
type PriceInterval ¶
type PriceInterval string
PriceInterval represents billing recurrence.
const ( IntervalDay PriceInterval = "day" IntervalWeek PriceInterval = "week" IntervalMonth PriceInterval = "month" IntervalYear PriceInterval = "year" )
type Product ¶
type Product struct {
ID string
Name string
Description string
Active bool
Metadata *json.RawMessage
Features *json.RawMessage
StripeCreatedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
Product mirrors a Stripe product stored locally.
type ProvisionFeature ¶ added in v0.0.3
type ProvisionFeature struct {
Name string `json:"name"`
}
ProvisionFeature is a marketing feature displayed on Stripe-hosted surfaces.
type ProvisionParams ¶ added in v0.0.3
type ProvisionParams struct {
Product ProvisionProductParams `json:"product"`
Prices []ProvisionPriceParams `json:"prices"`
}
ProvisionParams describes a complete product with all its prices to create in Stripe in a single call. This is designed for use cases like a CLI that reads a JSON file and provisions an entire product catalogue at once.
Example usage with JSON:
raw, _ := os.ReadFile("product.json")
result, err := client.ProvisionProductFromJSON(ctx, raw)
Example usage programmatically:
result, err := client.ProvisionProduct(ctx, stripeflow.ProvisionParams{
Product: stripeflow.ProvisionProductParams{
Name: "My SaaS",
Description: "A great product",
},
Prices: []stripeflow.ProvisionPriceParams{
{
Nickname: "Monthly",
Currency: "usd",
UnitAmount: 2999,
Recurring: &stripeflow.ProvisionRecurringParams{Interval: "month"},
},
},
})
type ProvisionPriceInfo ¶ added in v0.0.3
type ProvisionPriceInfo struct {
PriceID string `json:"price_id"`
Nickname string `json:"nickname,omitempty"`
}
ProvisionPriceInfo describes a single price created during provisioning.
type ProvisionPriceParams ¶ added in v0.0.3
type ProvisionPriceParams struct {
// Nickname is a human-readable label for the price (e.g. "Growth — monthly").
Nickname string `json:"nickname,omitempty"`
// Currency is a 3-letter ISO 4217 code, e.g. "usd" (required).
Currency string `json:"currency"`
// BillingScheme is "per_unit" (default) or "tiered".
BillingScheme string `json:"billing_scheme,omitempty"`
// UnitAmount is the price in the smallest currency unit (e.g. cents).
UnitAmount int64 `json:"unit_amount"`
// Recurring configures billing recurrence. Nil for one-time prices.
Recurring *ProvisionRecurringParams `json:"recurring,omitempty"`
// TransformQuantity configures billing per N units (e.g. per 1000 API calls).
TransformQuantity *ProvisionTransformQtyParams `json:"transform_quantity,omitempty"`
// Metadata is optional key-value metadata attached to the price.
Metadata map[string]string `json:"metadata,omitempty"`
}
ProvisionPriceParams describes a price to create for the product.
type ProvisionProductParams ¶ added in v0.0.3
type ProvisionProductParams struct {
// Name is the product name (required).
Name string `json:"name"`
// Description is an optional product description.
Description string `json:"description,omitempty"`
// Images are optional URLs to product images.
Images []string `json:"images,omitempty"`
// Metadata is optional key-value metadata attached to the product.
Metadata map[string]string `json:"metadata,omitempty"`
// MarketingFeatures lists feature bullet points shown on Stripe-hosted pages.
MarketingFeatures []ProvisionFeature `json:"marketing_features,omitempty"`
}
ProvisionProductParams describes the product to create.
type ProvisionRecurringParams ¶ added in v0.0.3
type ProvisionRecurringParams struct {
// Interval is "day", "week", "month", or "year" (required for recurring prices).
Interval string `json:"interval"`
// IntervalCount defaults to 1 (every interval).
IntervalCount int64 `json:"interval_count,omitempty"`
// UsageType is "licensed" (default) or "metered".
UsageType string `json:"usage_type,omitempty"`
// Meter is the ID of the meter tracking usage for metered prices (stripe-go v82+).
// This replaces the legacy aggregate_usage field.
Meter string `json:"meter,omitempty"`
// AggregateUsage is accepted in JSON input for backward compatibility but
// is no longer sent to Stripe in v82+. Use Meter instead for metered billing.
AggregateUsage string `json:"aggregate_usage,omitempty"`
// MeterEventName will auto-create a meter with this event name during provisioning.
MeterEventName string `json:"meter_event_name,omitempty"`
// MeterDisplayName is the display name for the auto-created meter.
MeterDisplayName string `json:"meter_display_name,omitempty"`
}
ProvisionRecurringParams configures the billing cycle for a price.
type ProvisionResult ¶ added in v0.0.3
type ProvisionResult struct {
ProductID string `json:"product_id"`
Prices []ProvisionPriceInfo `json:"prices"`
}
ProvisionResult contains the IDs of all resources created by ProvisionProduct.
type ProvisionTransformQtyParams ¶ added in v0.0.3
type ProvisionTransformQtyParams struct {
// DivideBy is the divisor (e.g. 1000 to bill per 1000 units).
DivideBy int64 `json:"divide_by"`
// Round is "up" or "down".
Round string `json:"round"`
}
ProvisionTransformQtyParams configures billing per N units.
type RecurringParams ¶
type RecurringParams struct {
Interval PriceInterval
IntervalCount int64 // 1 = every interval, 3 = every 3 intervals, etc.
}
RecurringParams configures the billing cycle for a price.
type Subscription ¶
type Subscription struct {
ID int64
UserID string
StripeCustomerID string
StripeSubscriptionID string
StripePriceID string
StripeProductID string
Status SubscriptionStatus
TrialEndsAt *time.Time
CurrentPeriodStart *time.Time
CurrentPeriodEnd *time.Time
CanceledAt *time.Time
UsageCount int64
UsageLimit *int64
Metadata *json.RawMessage
CreatedAt time.Time
UpdatedAt time.Time
}
Subscription represents a user's Stripe subscription state as stored locally.
func SubscriptionFromContext ¶
func SubscriptionFromContext(ctx context.Context) (*Subscription, bool)
SubscriptionFromContext retrieves the Subscription stored in the request context by the RequireSubscription middleware.
func (*Subscription) IsActive ¶
func (s *Subscription) IsActive() bool
IsActive reports whether the subscription is in an active or trialing state.
func (*Subscription) TrialExpired ¶
func (s *Subscription) TrialExpired() bool
TrialExpired reports whether the user's trial period has ended.
func (*Subscription) UsageLimitReached ¶
func (s *Subscription) UsageLimitReached() bool
UsageLimitReached reports whether the user has exhausted their usage allowance.
type SubscriptionStatus ¶
type SubscriptionStatus string
SubscriptionStatus mirrors Stripe's subscription statuses plus internal sentinels.
const ( StatusActive SubscriptionStatus = "active" StatusTrialing SubscriptionStatus = "trialing" StatusPastDue SubscriptionStatus = "past_due" StatusCanceled SubscriptionStatus = "canceled" StatusIncomplete SubscriptionStatus = "incomplete" StatusIncompleteExpired SubscriptionStatus = "incomplete_expired" StatusUnpaid SubscriptionStatus = "unpaid" StatusPaused SubscriptionStatus = "paused" // StatusNone means no Stripe subscription exists yet for this user. StatusNone SubscriptionStatus = "none" )
func (SubscriptionStatus) IsActive ¶
func (s SubscriptionStatus) IsActive() bool
IsActive reports whether the status is billable / accessible.
type SyncResult ¶
SyncResult summarises a full catalogue synchronisation.