Help us shape the future of Go! Take the 2026 Go Developer Survey

commerce

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: AGPL-3.0 Imports: 51 Imported by: 0

Documentation

Overview

Package commerce sells access to MCP servers: products → Stripe Checkout → orders → customers → entitlements → provisioning on billing servers over the signed mcp-billing/v1 protocol (spec §4.6, docs/COMMERCE.md).

Index

Constants

View Source
const (
	ProductProvisioning = "provisioning"
	ProductService      = "service"
	ProductDigital      = "digital"
)

Product is a provisioning plan, service or private digital download. PriceMinor is in the currency's minor unit (fils for AED). SEO uses the seo.FromMap keys.

View Source
const (
	OrderPending      = "pending"
	OrderPaid         = "paid"
	OrderProvisioning = "provisioning"
	OrderActive       = "active"
	OrderFailed       = "failed"
	OrderRefunded     = "refunded"
	OrderCancelled    = "cancelled"
)

Order statuses.

View Source
const (
	EntitlementPending   = "pending"
	EntitlementActive    = "active"
	EntitlementSuspended = "suspended"
	EntitlementExpired   = "expired"
	EntitlementFailed    = "failed"
)

Entitlement statuses.

View Source
const (
	ServerUnknown = "unknown"
	ServerOK      = "ok"
	ServerError   = "error"
)

Server statuses.

View Source
const (
	SettingCurrency      = "commerce.currency"
	SettingStripeSecret  = "commerce.stripe_secret_key"     // db.Encrypt, AAD = key
	SettingWebhookSecret = "commerce.stripe_webhook_secret" // db.Encrypt, AAD = key

)

Setting keys.

View Source
const (
	PermManage     = "commerce.manage"
	PermViewOrders = "commerce.view_orders"
)

Permissions.

View Source
const (
	JobProvision            = "commerce.provision"
	JobSuspend              = "commerce.suspend"
	JobMagicMail            = "commerce.magic_mail"
	CronExpire              = "commerce.expire"
	HookOrderPaid           = "commerce.order.paid"
	HookEntitlementActivate = "commerce.entitlement.activated"
)

Job kinds and hook names.

Variables

View Source
var (
	ErrNotFound            = errors.New("commerce: not found")
	ErrStripeNotConfigured = errors.New("commerce: Stripe is not configured")
	ErrInvalidSignature    = errors.New("commerce: invalid Stripe webhook signature")
	ErrNotActive           = errors.New("commerce: entitlement is not active")
	ErrNoServer            = errors.New("commerce: entitlement has no reachable billing server")
	ErrPeriodEnded         = errors.New("commerce: the entitlement period has ended")
)

Errors returned by the service.

Functions

func FormatPrice

func FormatPrice(minor int64, currency string) string

FormatPrice renders minor units as a major-unit decimal string ("12.50").

func ParsePrice

func ParsePrice(s, currency string) (int64, error)

ParsePrice converts a major-unit amount ("12.5", "12,50") to minor units of currency. It rejects negatives and more decimals than the currency has.

func Slugify

func Slugify(s string) string

Slugify lowercases s and joins its letter/digit runs with "-" (Arabic letters are kept).

Types

type AccountSettings

type AccountSettings struct {
	RegistrationEnabled bool `json:"registration_enabled"`
}

AccountSettings controls native customer registration only. Registration does not grant paid access or claim verified ownership of an email address.

type ActionResponse

type ActionResponse struct {
	Entitlement *Entitlement `json:"entitlement"`
}

ActionResponse is returned by entitlement actions.

type Cart

type Cart struct {
	Lines      []CartLine `json:"lines"`
	TotalMinor int64      `json:"total_minor"`
	Currency   string     `json:"currency"`
	Key        string     `json:"key"`
}

type CartCheckout

type CartCheckout struct {
	Intake         map[string]map[string]string `json:"intake,omitempty"`
	Items          []CartItem                   `json:"items"`
	Email          string                       `json:"email"`
	Name           string                       `json:"name"`
	Notes          string                       `json:"notes"`
	IdempotencyKey string                       `json:"idempotency_key"`
}

type CartItem

type CartItem struct {
	ProductID string `json:"product_id"`
	Quantity  int    `json:"quantity"`
}

type CartLine

type CartLine struct {
	Product    Product `json:"product"`
	Quantity   int     `json:"quantity"`
	TotalMinor int64   `json:"total_minor"`
}

type Catalog

type Catalog struct {
	Product map[string]any  `json:"product,omitempty"`
	Plans   []Plan          `json:"plans"`
	Tools   []any           `json:"tools,omitempty"`
	Raw     json.RawMessage `json:"raw,omitempty"`
}

Catalog is a billing server's GET /catalog data. Raw keeps the full payload (tools, product description…).

type DeleteResponse

type DeleteResponse struct {
	ID      string `json:"id"`
	Deleted bool   `json:"deleted"`
}

DeleteResponse is returned by DELETE operations.

type Entitlement

type Entitlement struct {
	ID          string         `json:"id"`
	CustomerID  string         `json:"customer_id"`
	Email       string         `json:"email"`
	OrderID     string         `json:"order_id"`
	OrderNumber string         `json:"order_number"`
	ProductID   string         `json:"product_id"`
	ProductName string         `json:"product_name"`
	ServerID    string         `json:"server_id"`
	ServerName  string         `json:"server_name"`
	PlanCode    string         `json:"plan_code"`
	ExternalID  string         `json:"external_id"`
	Status      string         `json:"status"`
	StartsAt    string         `json:"starts_at"`
	EndsAt      string         `json:"ends_at"`
	LastSyncAt  string         `json:"last_sync_at"`
	Meta        map[string]any `json:"meta"`
	CreatedAt   string         `json:"created_at"`
}

Entitlement is a customer's access to a plan on a billing server, created by exactly one order.

type IntakeField

type IntakeField struct {
	Key       string `json:"key"`
	Label     string `json:"label"`
	Required  bool   `json:"required"`
	MaxLength int    `json:"max_length"`
}

type ListQuery

type ListQuery struct {
	Search, Status string
	CustomerID     string
	Page, PerPage  int
}

ListQuery filters Orders and Entitlements. Search matches the email or order number; Status filters exactly. Page/PerPage default 1/20 (max 100).

type MCBBError

type MCBBError struct {
	Status  int
	Message string
}

MCBBError is a failed billing-server call. Status is the HTTP status (0 for transport failures). Retryable reports transient failures (transport, 408, 429, 5xx), mirroring the PHP client's retry rule.

func (*MCBBError) Error

func (e *MCBBError) Error() string

func (*MCBBError) Retryable

func (e *MCBBError) Retryable() bool

Retryable reports whether the call may succeed when retried.

type Module

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

Module is the commerce kernel.Module.

func New

func New() *Module

New returns the commerce module.

func (*Module) Catalogs

func (*Module) Catalogs() fs.FS

Catalogs implements kernel.CatalogProvider.

func (*Module) Migrations

func (*Module) Migrations() fs.FS

Migrations implements kernel.Module.

func (*Module) Name

func (*Module) Name() string

Name implements kernel.Module.

func (*Module) Register

func (m *Module) Register(d *kernel.Deps) error

Register publishes kernel.ServiceCommerce and wires jobs, theme kinds and funcs, public routes, the Stripe webhook, admin screens, API operations and health checks.

type Order

type Order struct {
	ReceiptStatus       string         `json:"receipt_status,omitempty"`
	ReceiptError        string         `json:"receipt_error,omitempty"`
	ReceiptSentAt       string         `json:"receipt_sent_at,omitempty"`
	RequestStatus       string         `json:"request_status"`
	FulfillmentNote     string         `json:"fulfillment_note"`
	ID                  string         `json:"id"`
	Number              string         `json:"number"`
	CustomerID          string         `json:"customer_id"`
	Email               string         `json:"email"`
	Status              string         `json:"status"`
	Currency            string         `json:"currency"`
	TotalMinor          int64          `json:"total_minor"`
	ProductID           string         `json:"product_id"`
	ProductName         string         `json:"product_name"`
	ProductSnapshot     map[string]any `json:"product_snapshot"`
	StripeSessionID     string         `json:"stripe_session_id"`
	StripePaymentIntent string         `json:"stripe_payment_intent"`
	PaidAt              string         `json:"paid_at"`
	CreatedAt           string         `json:"created_at"`
	UpdatedAt           string         `json:"updated_at"`
}

Order freezes a single Stripe product or the line items of a manual request.

type OrderItem

type OrderItem struct {
	Intake       map[string]string `json:"intake,omitempty"`
	IntakeSchema []IntakeField     `json:"intake_schema,omitempty"`
	ID           string            `json:"id"`
	ProductID    string            `json:"product_id"`
	Quantity     int               `json:"quantity"`
	UnitMinor    int64             `json:"unit_minor"`
	ProductName  string            `json:"product_name"`
	Kind         string            `json:"kind"`
	DownloadURL  string            `json:"download_url,omitempty"`
}

type Plan

type Plan struct {
	Code   string `json:"code"`
	Name   string `json:"name"`
	NameAr string `json:"name_ar,omitempty"`
}

Plan is one plan advertised by a billing server's GET /catalog.

type Product

type Product struct {
	Intake           []IntakeField  `json:"intake,omitempty"`
	Kind             string         `json:"kind"`
	DigitalFile      string         `json:"digital_file,omitempty"`
	DownloadDays     int            `json:"download_days"`
	ID               string         `json:"id"`
	Slug             string         `json:"slug"`
	Name             string         `json:"name"`
	Description      string         `json:"description"`
	ShortDescription string         `json:"short_description"`
	PriceMinor       int64          `json:"price_minor"`
	Currency         string         `json:"currency"`
	Active           bool           `json:"active"`
	GroupSlug        string         `json:"group_slug"`
	GroupName        string         `json:"group_name"`
	PlanCode         string         `json:"plan_code"`
	ServerID         string         `json:"server_id"`
	AccessMonths     int            `json:"access_months"`
	Features         []string       `json:"features"`
	ImageMediaID     string         `json:"image_media_id"`
	Sort             int            `json:"sort"`
	SEO              map[string]any `json:"seo"`
	WPProductID      string         `json:"wp_product_id"`
}

type ProductGroup

type ProductGroup struct {
	Slug, Name string
	Products   []Product
}

ProductGroup is a shop section: active products sharing GroupSlug.

type RequestDetail

type RequestDetail struct {
	Order *Order      `json:"order"`
	Items []OrderItem `json:"items"`
}

type RequestUpdate

type RequestUpdate struct {
	Status string `json:"status"`
	Note   string `json:"note"`
}

type Server

type Server struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	BaseURL     string `json:"base_url"`
	ClientID    string `json:"client_id"`
	Secret      string `json:"secret,omitempty"`
	SecretSet   bool   `json:"secret_set"`
	Protocol    string `json:"protocol"`
	Status      string `json:"status"`
	LastCheckAt string `json:"last_check_at"`
	LastError   string `json:"last_error"`
}

Server is a billing server speaking the mcp-billing/v1 protocol. Secret is write-only: SaveServer encrypts it when non-empty (empty keeps the stored secret) and reads never return it; SecretSet reports whether one exists.

type ServerTestResponse

type ServerTestResponse struct {
	OK      bool    `json:"ok"`
	Error   string  `json:"error,omitempty"`
	Catalog Catalog `json:"catalog"`
}

ServerTestResponse is returned by POST /v1/commerce/servers/{id}/test.

type Service

type Service interface {
	Products(ctx context.Context, activeOnly bool) ([]Product, error)
	Product(ctx context.Context, slug string) (*Product, error)
	SaveProduct(ctx context.Context, p Product) (*Product, error)
	DeleteProduct(ctx context.Context, id string) error

	UpsertFromWP(ctx context.Context, wp WPProduct) (*Product, error)
	// ReplaceMediaRef re-points every product image from media oldID to
	// newID (the migrator replaced a re-imported file).
	ReplaceMediaRef(ctx context.Context, oldID, newID string) error

	SubmitCart(ctx context.Context, request CartCheckout) (*Order, error)
	UpdateRequest(ctx context.Context, id string, request RequestUpdate) (*Order, error)
	StartCheckout(ctx context.Context, productID, email string) (redirectURL string, orderID string, err error)
	HandleStripeEvent(ctx context.Context, payload []byte, sigHeader string) error

	Orders(ctx context.Context, q ListQuery) ([]Order, int, error)
	Entitlements(ctx context.Context, q ListQuery) ([]Entitlement, int, error)
	CustomerEntitlements(ctx context.Context, userID string) ([]Entitlement, error)

	Suspend(ctx context.Context, entitlementID string) error
	Resume(ctx context.Context, entitlementID string) error
	Reconcile(ctx context.Context, entitlementID string) error
	LoginLink(ctx context.Context, entitlementID string) (string, error)

	Servers(ctx context.Context) ([]Server, error)
	SaveServer(ctx context.Context, s Server) error
	TestServer(ctx context.Context, id string) (Catalog, error)
}

Service is the commerce API published as kernel.ServiceCommerce.

type ValidationError

type ValidationError struct{ Fields map[string]string }

ValidationError carries per-field i18n keys (implements api.FieldErrorer).

func (*ValidationError) Error

func (e *ValidationError) Error() string

func (*ValidationError) FieldErrors

func (e *ValidationError) FieldErrors() map[string]string

FieldErrors implements api.FieldErrorer.

type WPProduct

type WPProduct struct {
	ID                                        int
	Slug, Name, Description, ShortDescription string
	PriceMinor                                int64
	Currency                                  string
	Categories                                []string
	ImageURLs                                 []string
	Meta                                      map[string]string
}

WPProduct is a WooCommerce catalog product as read by the migrator (its adapter maps an identical struct 1:1). Meta holds WooCommerce meta_data (e.g. _mcbb_server_id, _mcbb_plan_code, _mcbb_months).

Directories

Path Synopsis
Package fakebilling is an in-memory billing server implementing the mcp-billing/v1 protocol (see docs/COMMERCE.md) for tests and local e2e runs: signature verification (same scheme as the real servers), Idempotency-Key replay on mutations, and failure injection.
Package fakebilling is an in-memory billing server implementing the mcp-billing/v1 protocol (see docs/COMMERCE.md) for tests and local e2e runs: signature verification (same scheme as the real servers), Idempotency-Key replay on mutations, and failure injection.

Jump to

Keyboard shortcuts

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