purchases

package
v0.0.14 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package purchases sells products and subscriptions through the App Store and Google Play.

nimbus native plugin add purchases

items, err := purchases.Products(ctx, "pro_monthly", "coins_100")
r, err := purchases.Buy(ctx, "pro_monthly")
// Check r on your server, unlock what they paid for, then:
err = purchases.Finish(ctx, r)

A purchase that isn't finished comes back from Owned, so nothing is lost if the app dies halfway, but Google Play refunds one left for three days. To let Cashier do the checking, use a Cashier.

Index

Constants

This section is empty.

Variables

View Source
var ErrPending = errors.New("purchases: waiting for approval")

ErrPending means the purchase is waiting on someone: a parent's approval or a cash payment. It turns up in Owned once it goes through.

Functions

func Consume

func Consume(ctx context.Context, r Receipt) error

Consume is Finish for something used up, like coins, so that they can buy it again.

func Finish

func Finish(ctx context.Context, r Receipt) error

Finish tells the store they've got what they paid for. Call it after your server has accepted the receipt, not before.

Types

type Cashier

type Cashier struct {
	Key  string // your app's public key, never the secret one
	User string // your own ID for this person
	URL  string // for a self-hosted Nimbus Cloud; empty is nimbusgo.space
}

Cashier sends receipts to Nimbus Cashier, which checks them with the stores and keeps track of who's entitled to what, so you don't need a server of your own for it.

cashier := purchases.Cashier{Key: "cshr_pub_...", User: userID}
r, err := purchases.Buy(ctx, "pro_monthly")
who, err := cashier.Deliver(ctx, r)
if who.Entitled("pro") { ... }

func (Cashier) Customer

func (c Cashier) Customer(ctx context.Context) (Customer, error)

Customer asks Cashier what they're entitled to.

func (Cashier) Deliver

func (c Cashier) Deliver(ctx context.Context, r Receipt) (Customer, error)

Deliver gives Cashier a receipt and finishes the purchase once it's accepted. If Cashier can't be reached the purchase stays unfinished, and Sync delivers it later.

func (Cashier) Sync

func (c Cashier) Sync(ctx context.Context, receipts ...Receipt) (Customer, error)

Sync tells Cashier everything this phone owns: call it when the app opens, and from a "Restore purchases" button with the receipts from Restore. With no receipts it uses Owned.

type CashierError

type CashierError struct {
	Status  int    // the HTTP status
	Code    string `json:"error"`   // its reason, such as "invalid_receipt"
	Message string `json:"message"` // for you, not for showing to people
}

CashierError is Cashier turning a request down. Code is its reason, such as "invalid_receipt".

func (*CashierError) Error

func (e *CashierError) Error() string

type Customer

type Customer struct {
	User         string    `json:"subject"`                // your ID for them
	Entitlements []string  `json:"active_entitlement_ids"` // what they have now
	Products     []string  `json:"active_product_ids"`     // the products behind those
	Expires      time.Time `json:"latest_expires_at"`      // zero if nothing expires
}

Customer is what Cashier knows about someone.

func (Customer) Entitled

func (c Customer) Entitled(id string) bool

Entitled reports whether they have an entitlement now.

type Product

type Product struct {
	ID          string  `json:"id"`          // its ID in the store
	Title       string  `json:"title"`       // its name, in their language
	Description string  `json:"description"` // what it is, in their language
	Price       string  `json:"price"`       // ready to show: "₹499.00"
	Amount      float64 `json:"amount"`      // the price as a number
	Currency    string  `json:"currency"`    // such as "INR"
	// Period is how often a subscription renews, such as "P1M" or "P1Y".
	// It's empty for anything else.
	Period string `json:"period"`
}

Product is something on sale, priced for this person's store.

func Products

func Products(ctx context.Context, ids ...string) ([]Product, error)

Products looks up what's on sale. Any ID the store doesn't know is left out.

type Receipt

type Receipt struct {
	Platform    string `json:"platform"`              // "apple" or "google"
	ProductID   string `json:"productId"`             // what they bought
	ID          string `json:"id"`                    // this purchase, for Finish and Consume
	Token       string `json:"token"`                 // the store's signed proof
	RenewalInfo string `json:"renewalInfo,omitempty"` // Apple's, for a subscription
	Finished    bool   `json:"finished"`              // whether it has been finished
}

Receipt is the store's signed proof of a purchase. Send it to your server, which asks the store whether it's real: never trust it on the phone.

func Buy

func Buy(ctx context.Context, id string) (Receipt, error)

Buy opens the store's payment sheet. If they back out the error has code plugin.Cancelled; if someone must approve it, the error is ErrPending.

func Owned

func Owned(ctx context.Context) ([]Receipt, error)

Owned lists what they have now, and anything bought but not finished. Look at it when the app opens: that's how a renewal, a purchase made on another device, or one interrupted by a crash reaches you.

func Restore

func Restore(ctx context.Context) ([]Receipt, error)

Restore is Owned behind a "Restore purchases" button. Apple requires one, and asks them to sign in to the App Store.

Jump to

Keyboard shortcuts

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