Documentation ¶
Overview ¶
package stripeutil provides some utility functions and data structures for working with the Stripe API for builing a SaaS application. This provides simple ways of creating Customers and Subscriptions, and storing them in a user defined data store along with their PaymentMethods and Invoices. This also provides a simple way of handling webhook events that are emitted from Stripe.
stripeutil.Stripe is the main way to interact with the Stripe API. This is supposed to be used along with the stripeutil.Store interface which allows for storing the resources retrieved from Stripe. Below is a brief example as to how this library would be used to implement a subscription flow,
stripe := stripeutil.New(os.Getenv("STRIPE_SECRET"), store) c, err := stripe.Customer("me@example.com") if err != nil { panic(err) // Don't actually do this. } // Assume the payment method ID has been passed through the a client, as // opposed to being hardcoded. pm, err := stripeutil.RetrievePaymentMethod(stripe, "pm_123456") if err != nil { panic(err) // Handle error properly. } // Create a subscription for the given customer with the given payment // method. sub, err := stripe.Subscribe(c, pm, Params{ "items": []Params{ {"price": "price_123456"}, }, }) if err != nil { panic(err) // Be more graceful when you do this. }
the above code will first lookup the customer via the given stripeutil.Store implementation we pass. If a customer cannot be found then one is created in Stripe with the given email address and subsequently stored, before being returned. After this, we then retrieve the given payment method from Stripe, and pass this, along with the customer to the Subscribe call. We also specify the request parameters we wish to have set when creating a subscription in Stripe. Under the hood, stripeutil.Stripe will do the following when Subscribe is called,
- Retrieve the subscription for the given customer from the underlying store
- Attach the given payment method to the given customer
- Update the customer's default payment method to what was given
- Store the given payment method in the underlying store
- Return the subscription for the given customer, if one was found otherwise...
- ...a new subscription is created for the customer, and returned if the invoice status is valid
And below is how a cancellation flow of a subscription would work with this library,
c, err := stripe.Customer("me@example.com") if err != nil { panic(err) // If a recover is used then a panic is fine right? } if err := stripe.Unsubscribe(c); err != nil { panic(err) // Let's hope a recover is somewhere... }
with the above, we lookup the customer similar to how we did before, and pass them to the Unsubscribe call. This will update the customer's subscription to cancel at the end period, and update the subscription in the underlying store. However, if the customer's subscription cannot be found in the underlying store, or is not valid then nothing happens and nil is returned.
stripeutil.Store is an interface that allows for storing the resources retrieved from Stripe. An implementation of this interface for PostgreSQL comes with this library out of the box. stripeutil.Stripe, depends on this interface for storing the customer, invoice, and subscription invoices during the Subscribe flow.
stripeutil.Stripe is what is primarily used for interfacing with the Stripe API. This depends on the stripeutil.Store interface, as previously mentioned, for storing the resources retrieved from Stripe.
stripeutil.Params allows for specifying the request parameters to set in the body of the request sent to Stripe. This is encoded to x-www-url-formencoded, when sent in a request, for example,
stripeutil.Params{ "invoice_settings": stripeutil.Params{ "default_payment_method": "pm_123456", }, }
would be encoded to,
invoice_settings[default_payment_method]=pm_123456
stripeutil.Stripe has a Post method that accepts a stripeutil.Params argument, this can be used for making more explicit calls to Stripe,
resp, err := stripe.Post("/v1/payment_intents", stripeutil.Params{ "amount": 2000, "currency": "gbp", "payment_method_types": []string{"card"}, })
the returned *http.Response can be used as usual.
stripeutil.Client is a thin HTTP client for the Stripe API. All HTTP requests made through this client will be configured to talk to Stripe. This is embedded inside of stripeutil.Stripe so you can do stuff like,
resp, err := stripe.Get("/v1/customers")
for example, to get the customers you have. A new client can be created via stripeutil.NewClient, and through this you can configured which version of the Stripe API to use,
client := stripeutil.NewClient("2006-01-02", os.Getenv("STRIPE_SECRET"))
If using an older/newer version of the Stripe API this way then it is highly recommended that you do not use stripeutil.Stripe and instead perform all interactions via stripeutil.Client. This is because stripeutil.Stripe relies on the stripe/stripe-go SDK, so the versions may not match if you do this.
Index ¶
- Variables
- type Client
- type Customer
- type ErrPaymentIntent
- type Error
- type HookHandler
- type HookHandlerFunc
- type Invoice
- type PSQL
- func (p PSQL) DefaultPaymentMethod(c *Customer) (*PaymentMethod, bool, error)
- func (p PSQL) Invoices(c *Customer) ([]*Invoice, error)
- func (p PSQL) LogEvent(id string) error
- func (p PSQL) LookupCustomer(email string) (*Customer, bool, error)
- func (p PSQL) LookupInvoice(c *Customer, number string) (*Invoice, bool, error)
- func (p PSQL) PaymentMethods(c *Customer) ([]*PaymentMethod, error)
- func (p PSQL) Put(r Resource) error
- func (p PSQL) Remove(r Resource) error
- func (p PSQL) Subscription(c *Customer) (*Subscription, bool, error)
- type Params
- type PaymentMethod
- type Resource
- type Store
- type Stripe
- func (s *Stripe) Customer(email string) (*Customer, error)
- func (s *Stripe) Post(uri string, params Params) (*http.Response, error)
- func (s *Stripe) Resubscribe(c *Customer) error
- func (s *Stripe) Subscribe(c *Customer, pm *PaymentMethod, params Params) (*Subscription, error)
- func (s *Stripe) Unsubscribe(c *Customer) (*Subscription, error)
- type Subscription
- func (s *Subscription) Cancel(st *Stripe) error
- func (s *Subscription) Endpoint(uris ...string) string
- func (s *Subscription) Load(st *Stripe) error
- func (s *Subscription) Reactivate(st *Stripe) error
- func (s *Subscription) Update(st *Stripe, params Params) error
- func (s *Subscription) Valid() bool
- func (s *Subscription) WithinGrace() bool
- type TaxRate
- type Taxes
Constants ¶
This section is empty.
Variables ¶
var ( ErrEventExists = errors.New("event exists") ErrUnknownResource = errors.New("unknown resource") )
var ( // ErrUnknownJurisdiction denotes when a jurisdiction cannot be found in // the set of tax rates. ErrUnknownJurisdiction = errors.New("unknown jurisdiction") )
Functions ¶
This section is empty.
Types ¶
type Client ¶
Client is a simple HTTP client for the Stripe API. This can be configured to use specific version of the Stripe API. Each request made via this client will be automatically configured to talk to the Stripe API with the necessary headers.
func NewClient ¶
NewClient configures a new Client for interfacing with the Stripe API using the given version, and secret for authentication.
func (Client) Error ¶
Error decodes an error from the Stripe API from the given http.Response and returns it as a pointer to Error.
type Customer ¶
type Customer struct { *stripe.Customer Jurisdiction string }
Customer is the Customer resource from Stripe. Embedded in this struct is the stripe.Customer struct from Stripe.
func CreateCustomer ¶
CreateCustomer creates a new Customer in Stripe with the given Params and returns it.
type ErrPaymentIntent ¶
type ErrPaymentIntent struct { ID string Status stripe.PaymentIntentStatus }
ErrPaymentIntent represents a PaymentIntent with an invalid status. This will contain the ID of the original PaymentIntent, and the status that caused the error in the first place.
func (ErrPaymentIntent) Error ¶
func (e ErrPaymentIntent) Error() string
type Error ¶
type HookHandler ¶
type HookHandler struct {
// contains filtered or unexported fields
}
HookHandler provides a way of registering handlers against the different events emitted by Stripe.
func NewHookHandler ¶
func NewHookHandler(secret string, s Store, errh func(error)) *HookHandler
NewHookHandler returns a HookHandler using the given secret for request verification, and the given callback for handling any errors that occur during request verification.
func (*HookHandler) Handle ¶
func (h *HookHandler) Handle(event string, fn HookHandlerFunc)
Handler registers a new handler for the given event. If a handler was already registered against the given event, then that handler will be overwritten with the new handler.
func (*HookHandler) HandlerFunc ¶
func (h *HookHandler) HandlerFunc(w http.ResponseWriter, r *http.Request)
HandlerFunc should be registered in the route multiplexer being used to register routes in the web server. For example,
mux := http.NewServeMux() mux.HandleFunc("/stripe-hook", hook.HandlerFunc)
this would cause the HookHandler to handle all of the requests sent to the "/stripe-hook" endpoint.
type HookHandlerFunc ¶
type HookHandlerFunc func(stripe.Event, http.ResponseWriter, *http.Request)
HookHandlerFunc is the handler function that is registered agains an event. This is like an http.HandlerFunc, only the first argument it is passed is the decoded event sent from stripe.
type Invoice ¶
type Invoice struct { *stripe.Invoice Updated time.Time // Updated is when the Invoice was last updated. }
Invoice is the Invoice resource from Striped. Embedded in this struct is the stripe.Invoice struct from Stripe.
func RetrieveUpcomingInvoice ¶
RetrieveUpcomingInvoice will retrieve the upcoming Invoice for the given Customer.
type PSQL ¶
PSQL provides a way of storing Stripe resources within PostgreSQL. This will store the Customer, Invoice, PaymentMethod, and Subscription resource. Using this implementation of the Store interface would require having the following schema,
CREATE TABLE stripe_customers ( id VARCHAR NOT NULL UNIQUE, email VARCHAR NOT NULL UNIQUE, jurisdiction VARCHAR NULL, created_at TIMESTAMP NOT NULL ); CREATE TABLE stripe_events ( id VARCHAR NOT NULL UNIQUE ); CREATE TABLE stripe_invoices ( id VARCHAR NOT NULL UNIQUE, customer_id VARCHAR NOT NULL, number VARCHAR NOT NULL, amount NUMERIC NOT NULL, status VARCHAR NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL ); CREATE TABLE stripe_payment_methods ( id VARCHAR NOT NULL UNIQUE, customer_id VARCHAR NOT NULL, type VARCHAR NOT NULL, info JSON NOT NULL, is_default BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP NOT NULL ); CREATE TABLE stripe_subscriptions ( id VARCHAR NOT NULL UNIQUE, customer_id VARCHAR NOT NULL, status VARCHAR NOT NULL, started_at TIMESTAMP NOT NULL, ends_at TIMESTAMP NULL );
func (PSQL) DefaultPaymentMethod ¶
func (p PSQL) DefaultPaymentMethod(c *Customer) (*PaymentMethod, bool, error)
DefaultPaymentMethod will get the default PaymentMethod for the given Customer from the stripe_payment_methods table along with whether or not the PaymentMethod could be found.
func (PSQL) LookupCustomer ¶
LookupCustomer will lookup the Customer by the given email in the stripe_customers table and return them along with whether or not the Customer could be found.
func (PSQL) LookupInvoice ¶
func (PSQL) PaymentMethods ¶
func (p PSQL) PaymentMethods(c *Customer) ([]*PaymentMethod, error)
PaymentMethods returns all of the PaymentMethods for the given Customer from the stripe_payment_methods table.
func (PSQL) Put ¶
Put will put the given Resource into the PostgreSQL database. If the given Resource already exists then it will be updated in the respective table.
func (PSQL) Subscription ¶
func (p PSQL) Subscription(c *Customer) (*Subscription, bool, error)
Subscription will get the Subscription for the given Customer from the stripe_subscriptions table and return it along with whether or not the Subscription could be found.
type Params ¶
type Params map[string]interface{}
Params is used for defining the parameters that are passed in the body of a Request made to the Stripe API. This will be encoded into a valid x-www-form-urlencoded payload.
type PaymentMethod ¶
type PaymentMethod struct { *stripe.PaymentMethod Default bool // Default is whether or not this is a default PaymentMethod for the Customer. }
PaymentMethod is the PaymentMethod resource from Stripe. Embedded in this struct is the stripe.PaymentMethod struct from Stripe.
func RetrievePaymentMethod ¶
func RetrievePaymentMethod(s *Stripe, id string) (*PaymentMethod, error)
RetrievePaymentMethod will get the PaymentMethod of the given ID from Stripe and return it.
func (*PaymentMethod) Attach ¶
func (pm *PaymentMethod) Attach(s *Stripe, c *Customer) error
Attach will attach the current PaymentMethod to the given Customer.
func (*PaymentMethod) Detach ¶
func (pm *PaymentMethod) Detach(s *Stripe) error
Detach will detach the current PaymentMethod from the Customer it was previously attached to.
func (*PaymentMethod) Endpoint ¶
func (pm *PaymentMethod) Endpoint(uris ...string) string
Endpoint implements the Resource interface.
func (*PaymentMethod) Load ¶
func (pm *PaymentMethod) Load(s *Stripe) error
Load implements the Resource interface.
type Resource ¶
type Resource interface { // Endpoint will return the URI for the current Resource from the Stripe // API. The given uris will be appended to the final endpoint. If the // Resource does not have an ID set on it, then the base endpoint for the // Resource should be returned. Endpoint(uris ...string) string // Load will use the given Stripe client to load in the resource from the // Stripe API using the Resource's endpoint. This should overwrite the // fields in the Resource with the decoded response from Stripe. Load(s *Stripe) error }
Resource represents a resource that has been retrieved by Stripe.
type Store ¶
type Store interface { // LookupCustomer will lookup the customer by the given email from within // the underlying data store. Whether or not the customer could be found // is denoted by the returned bool value. LookupCustomer(email string) (*Customer, bool, error) // LookupInvoice will lookup the invoice for the given customer by the // given invoice number. Whether or not the invoice could be found is // denoted by the returned bool value. LookupInvoice(c *Customer, number string) (*Invoice, bool, error) // LogEvent will store the given event ID in the underlying store. If the // given event ID already exists, then this should return ErrEventExists. LogEvent(string) error // Subscription returns the subscription for the given Customer. Whether or // not the Customer has a subscription will be denoted by the returned bool // value. Subscription(c *Customer) (*Subscription, bool, error) // DefaultPaymentMethod returns the default payment method for the given // Customer. Whether or not the Customer has a default payment method is // denoted by the returned bool value. DefaultPaymentMethod(c *Customer) (*PaymentMethod, bool, error) // Invoices returns all of the invoices for the given customer. The returned // invoices should be sorted from newest to oldest. Invoices(c *Customer) ([]*Invoice, error) // PaymentMethods returns all of the payment methods that has been attached // to the given Customer. PaymentMethods(c *Customer) ([]*PaymentMethod, error) // Put will put the given Resource into the underlying data store. If the // given Resource already exists in the data store, then that should simply // be updated. If the given Resource is the PaymentMethod resource, then a // check should be done to ensure that only one PaymentMethod for a Customer // is the default PaymentMethod. Put(r Resource) error // Remove will remove the given Resource from the underlying data store. If // the given Resource cannot be found then this returns nil. Remove(r Resource) error }
Store provides an interface for storing and retrieving resources that have been received by the Stripe API in an underlying data store such as a database.
type Stripe ¶
Stripe provides a simple way of managing the flow of creating customers and subscriptions, and for storing them in a data store.
func New ¶
New configures a new Stripe client with the given secret for authenticatio and Store for storing/retrieving resources.
func (*Stripe) Customer ¶
Customer will get the Stripe customer by the given email. If a customer does not exist in the underlying data store then one is created via Stripe and subsequently stored in the underlying data store.
func (*Stripe) Resubscribe ¶
Resubscribe will reactivate the given Customer's Subscription, if that Subscription was canceled and lies within the grace period.
func (*Stripe) Subscribe ¶
func (s *Stripe) Subscribe(c *Customer, pm *PaymentMethod, params Params) (*Subscription, error)
Subscribe creates a new subscription for the given Customer using the given PaymentMethod. The given Params will be passed through directly to the request that creates the Subscription in Stripe. The given PaymentMethod and returned Subscription will be stored in the underlying data store. If the payment for the Subscription fails then this will be returned via ErrPaymentIntent.
func (*Stripe) Unsubscribe ¶
func (s *Stripe) Unsubscribe(c *Customer) (*Subscription, error)
Unsubscribe will cancel the subscription for the given Customer if that subscription exists, and is valid. This will cancel the subscription at the period end for the customer, and update it in the underlying store.
type Subscription ¶
type Subscription struct { *stripe.Subscription EndsAt sql.NullTime // EndsAt is the time the Subscription ends if it was cancelled. }
Subscription is the Subscription resource from Stripe. Embedded in this struct is the stripe.Subscription struct from Stripe.
func CreateSubscription ¶
func CreateSubscription(st *Stripe, params Params) (*Subscription, error)
CreateSubscription will create a new Subscription in Stripe with the given request Params.
func (*Subscription) Cancel ¶
func (s *Subscription) Cancel(st *Stripe) error
Cancel will cancel the current Subscription at the end of the Subscription Period. This will set the EndsAt field to the CurrentPeriodEnd of the Subscription.
func (*Subscription) Endpoint ¶
func (s *Subscription) Endpoint(uris ...string) string
Endpoint implements the Resource interface.
func (*Subscription) Load ¶
func (s *Subscription) Load(st *Stripe) error
Load implements the Resource interface.
func (*Subscription) Reactivate ¶
func (s *Subscription) Reactivate(st *Stripe) error
Reactivate will reactivate the current subscription by setting the property cancel_at_period_end to false. This will set the EndsAt field to be invalid.
func (*Subscription) Update ¶
func (s *Subscription) Update(st *Stripe, params Params) error
Update will update the current Subscription in Stripe with the given Params.
func (*Subscription) Valid ¶
func (s *Subscription) Valid() bool
Valid will return whether or not the current Subscription is valid. A Subscription is considered valid if the status is one of, "all", "active", or "trialing", or if the Subscription was cancelled but the current time is before the EndsAt date.
func (*Subscription) WithinGrace ¶
func (s *Subscription) WithinGrace() bool
WithinGrace will return true if the current Subscription has been canceled but stil lies within the grace period. If the Subscription has not been canceled then this will always return true.
type TaxRate ¶
type TaxRate struct {
*stripe.TaxRate
}
type Taxes ¶
type Taxes struct {
// contains filtered or unexported fields
}
Taxes provides a way of storing the tax rates configured in Stripe against their respective jurisdiction. You would typically use this if you are storing your tax rates in a file on disk, and want them loaded up at start time of your application.
func LoadTaxRates ¶
LoadTaxes will load in all of the tax rate IDs from the given io.Reader. It is expected for each tax rate ID to be on its own separate line. Comments (lines prefixed with #) are ignored. The given errh function is used for handling any errors that arise when calling out to Stripe.
func (*Taxes) Get ¶
Get returns the tax rate for the given jurisdiction, if it exists in the underlying store.
func (*Taxes) Reload ¶
Reload loads in new tax rate IDs from the given io.Reader. This will return an error if there is any issue with reading from the given io.Reader. Any errors that occur when loading in the tax rates via Stripe will be handled via the given errh callback. This will only load in the new tax rates that are found.