Ledger

Go Packages

Complete reference for all Ledger Go packages, types, and interfaces.

All Ledger packages are importable from github.com/xraph/ledger. The module is designed as a composable library -- import only the packages you need.

Core packages

github.com/xraph/ledger

Main engine and configuration. The root package provides the Ledger struct that coordinates all billing operations, plus re-exported convenience types.

// Constructor
func New(s store.Store, opts ...Option) *Ledger

// Lifecycle
func (l *Ledger) Start(ctx context.Context) error
func (l *Ledger) Stop() error

// Plan management
func (l *Ledger) CreatePlan(ctx context.Context, p *plan.Plan) error
func (l *Ledger) GetPlan(ctx context.Context, planID id.PlanID) (*plan.Plan, error)
func (l *Ledger) GetPlanBySlug(ctx context.Context, slug, appID string) (*plan.Plan, error)

// Subscription management
func (l *Ledger) CreateSubscription(ctx context.Context, sub *subscription.Subscription) error
func (l *Ledger) GetSubscription(ctx context.Context, subID id.SubscriptionID) (*subscription.Subscription, error)
func (l *Ledger) GetActiveSubscription(ctx context.Context, tenantID, appID string) (*subscription.Subscription, error)
func (l *Ledger) CancelSubscription(ctx context.Context, subID id.SubscriptionID, immediately bool) error

// Usage metering (non-blocking)
func (l *Ledger) Meter(ctx context.Context, featureKey string, quantity int64) error

// Entitlement checking
func (l *Ledger) Entitled(ctx context.Context, featureKey string) (*entitlement.Result, error)
func (l *Ledger) Remaining(ctx context.Context, featureKey string) (int64, error)

// Invoice generation
func (l *Ledger) GenerateInvoice(ctx context.Context, subID id.SubscriptionID) (*invoice.Invoice, error)

Functional options:

OptionDescription
WithLogger(*slog.Logger)Set the structured logger
WithPlugin(plugin.Plugin)Register a plugin for lifecycle hooks
WithMeterConfig(batchSize int, flushInterval time.Duration)Configure meter batching (default: 100 events, 5s)
WithEntitlementCacheTTL(time.Duration)Set entitlement cache TTL (default: 30s)

Re-exported types:

Type aliasOriginDescription
Moneytypes.MoneyType-safe monetary value
Entitytypes.EntityBase entity with timestamps

Re-exported constructors:

FunctionDescription
USD(cents int64)Create Money in US Dollars
EUR(cents int64)Create Money in Euros
GBP(pence int64)Create Money in British Pounds
JPY(yen int64)Create Money in Japanese Yen
CAD(cents int64)Create Money in Canadian Dollars
AUD(cents int64)Create Money in Australian Dollars
Zero(currency string)Create zero-value Money in any currency
Sum(values ...Money)Sum multiple Money values
NewEntity()Create Entity with current timestamps

Sentinel errors:

The root package defines all sentinel errors. They are grouped by category:

CategoryErrors
GeneralErrNotFound, ErrAlreadyExists, ErrInvalidInput, ErrUnauthorized, ErrForbidden
PlanErrPlanNotFound, ErrPlanArchived, ErrPlanInUse, ErrFeatureNotFound, ErrInvalidPricing, ErrDuplicateFeature
SubscriptionErrSubscriptionNotFound, ErrSubscriptionExists, ErrSubscriptionCanceled, ErrSubscriptionExpired, ErrInvalidUpgrade, ErrInvalidDowngrade, ErrTrialExpired, ErrNoActiveSubscription
MeteringErrMeterBufferFull, ErrInvalidQuantity, ErrDuplicateEvent, ErrEventTooOld
EntitlementErrQuotaExceeded, ErrFeatureDisabled, ErrHardLimitReached, ErrSoftLimitReached, ErrNoEntitlement
InvoiceErrInvoiceNotFound, ErrInvoiceFinalized, ErrInvoicePaid, ErrInvoiceVoided, ErrInvoiceIncomplete, ErrInvalidDiscount
CouponErrCouponNotFound, ErrCouponExpired, ErrCouponInvalid, ErrCouponExhausted, ErrCouponNotStarted
ProviderErrProviderNotFound, ErrProviderSync, ErrProviderWebhook, ErrProviderNotConfigured
StoreErrStoreNotReady, ErrStoreClosed, ErrTransactionFailed, ErrMigrationFailed
CacheErrCacheMiss, ErrCacheInvalidate

Error helpers:

func IsNotFound(err error) bool    // Checks all not-found variants
func IsQuotaError(err error) bool  // Checks all quota/limit variants
func IsRetryable(err error) bool   // Checks if the operation can be retried

Error types:

type ValidationError struct {
    Field   string
    Message string
}

type MultiError struct {
    Errors []error
}
func (e *MultiError) Add(err error)
func (e MultiError) HasErrors() bool
func (e MultiError) First() error

See Error Handling for the full error reference.


Entity packages

github.com/xraph/ledger/plan

Plan and feature definitions. A plan describes what features are available, at what limits, and at what price.

type Plan struct {
    types.Entity
    ID          id.PlanID
    Name        string
    Slug        string
    Description string
    Currency    string
    Status      Status            // "active", "archived", "draft"
    TrialDays   int
    Features    []Feature
    Pricing     *Pricing
    AppID       string
    Metadata    map[string]string
}

func (p *Plan) FindFeature(key string) *Feature
func (p *Plan) Allows(featureKey string, currentUsage int64) bool

Feature:

type Feature struct {
    types.Entity
    ID        id.FeatureID
    Key       string
    Name      string
    Type      FeatureType       // "metered", "boolean", "seat"
    Limit     int64             // -1 = unlimited
    Period    Period            // "monthly", "yearly", "none"
    SoftLimit bool
    Metadata  map[string]string
}

Pricing:

type Pricing struct {
    types.Entity
    ID            id.PriceID
    PlanID        id.PlanID
    BaseAmount    types.Money
    BillingPeriod Period
    Tiers         []PriceTier
}

type PriceTier struct {
    FeatureKey string
    Type       TierType          // "graduated", "volume", "flat"
    UpTo       int64
    UnitAmount types.Money
    FlatAmount types.Money
    Priority   int
}

Constants:

ConstantValues
StatusStatusActive, StatusArchived, StatusDraft
FeatureTypeFeatureMetered, FeatureBoolean, FeatureSeat
PeriodPeriodMonthly, PeriodYearly, PeriodNone
TierTypeTierGraduated, TierVolume, TierFlat

Store interface:

type Store interface {
    Create(ctx context.Context, p *Plan) error
    Get(ctx context.Context, planID id.PlanID) (*Plan, error)
    GetBySlug(ctx context.Context, slug string, appID string) (*Plan, error)
    List(ctx context.Context, appID string, opts ListOpts) ([]*Plan, error)
    Update(ctx context.Context, p *Plan) error
    Delete(ctx context.Context, planID id.PlanID) error
    Archive(ctx context.Context, planID id.PlanID) error
}

type ListOpts struct {
    Status Status
    Limit  int
    Offset int
}

See Plans for usage details.


github.com/xraph/ledger/subscription

Subscription lifecycle management. A subscription connects a tenant to a plan with status tracking, billing period management, and trial support.

type Subscription struct {
    types.Entity
    ID                 id.SubscriptionID
    TenantID           string
    PlanID             id.PlanID
    Status             Status
    CurrentPeriodStart time.Time
    CurrentPeriodEnd   time.Time
    TrialStart         *time.Time
    TrialEnd           *time.Time
    CanceledAt         *time.Time
    CancelAt           *time.Time
    EndedAt            *time.Time
    AppID              string
    ProviderID         string
    ProviderName       string
    Metadata           map[string]string
}

Constants:

ConstantValue
StatusActive"active"
StatusTrialing"trialing"
StatusPastDue"past_due"
StatusCanceled"canceled"
StatusExpired"expired"
StatusPaused"paused"

Store interface:

type Store interface {
    Create(ctx context.Context, s *Subscription) error
    Get(ctx context.Context, subID id.SubscriptionID) (*Subscription, error)
    GetActive(ctx context.Context, tenantID string, appID string) (*Subscription, error)
    List(ctx context.Context, tenantID string, appID string, opts ListOpts) ([]*Subscription, error)
    Update(ctx context.Context, s *Subscription) error
    Cancel(ctx context.Context, subID id.SubscriptionID, cancelAt time.Time) error
}

type ListOpts struct {
    Status Status
    Limit  int
    Offset int
}

See Subscriptions for usage details.


github.com/xraph/ledger/meter

Usage event tracking and batching. Events are collected in a high-throughput ring buffer and flushed to the store in configurable batches.

type UsageEvent struct {
    ID             id.UsageEventID
    TenantID       string
    AppID          string
    FeatureKey     string
    Quantity       int64
    Timestamp      time.Time
    IdempotencyKey string
    Metadata       map[string]string
}

Store interface:

type Store interface {
    IngestBatch(ctx context.Context, events []*UsageEvent) error
    Aggregate(ctx context.Context, tenantID, appID, featureKey string, period plan.Period) (int64, error)
    AggregateMulti(ctx context.Context, tenantID, appID string, featureKeys []string, period plan.Period) (map[string]int64, error)
    Query(ctx context.Context, tenantID, appID string, opts QueryOpts) ([]*UsageEvent, error)
    Purge(ctx context.Context, before time.Time) (int64, error)
}

type QueryOpts struct {
    FeatureKey string
    Start      time.Time
    End        time.Time
    Limit      int
    Offset     int
}

See Metering for usage details.


github.com/xraph/ledger/entitlement

Feature access checking with caching. The result struct carries full context about whether a feature is allowed and how much quota remains.

type Result struct {
    Allowed   bool   // Whether the feature is accessible
    Feature   string // Feature key that was checked
    Used      int64  // Current period usage
    Limit     int64  // Plan limit (-1 = unlimited)
    Remaining int64  // Remaining quota (-1 = unlimited)
    SoftLimit bool   // Whether the limit is soft (allows overage)
    Reason    string // Explanation when denied
}

Store interface:

type Store interface {
    GetCached(ctx context.Context, tenantID, appID, featureKey string) (*Result, error)
    SetCached(ctx context.Context, tenantID, appID, featureKey string, result *Result, ttl time.Duration) error
    Invalidate(ctx context.Context, tenantID, appID string) error
    InvalidateFeature(ctx context.Context, tenantID, appID, featureKey string) error
}

See Entitlements for usage details.


github.com/xraph/ledger/invoice

Invoice generation and line items. Invoices aggregate usage charges, base fees, taxes, and discounts into a detailed billing document.

type Invoice struct {
    types.Entity
    ID             id.InvoiceID
    TenantID       string
    SubscriptionID id.SubscriptionID
    Status         Status
    Currency       string
    Subtotal       types.Money
    TaxAmount      types.Money
    DiscountAmount types.Money
    Total          types.Money
    LineItems      []LineItem
    PeriodStart    time.Time
    PeriodEnd      time.Time
    DueDate        *time.Time
    PaidAt         *time.Time
    VoidedAt       *time.Time
    VoidReason     string
    PaymentRef     string
    ProviderID     string
    AppID          string
    Metadata       map[string]string
}

type LineItem struct {
    ID          id.LineItemID
    InvoiceID   id.InvoiceID
    FeatureKey  string
    Description string
    Quantity    int64
    UnitAmount  types.Money
    Amount      types.Money
    Type        LineItemType
    Metadata    map[string]string
}

Constants:

ConstantValues
StatusStatusDraft, StatusPending, StatusPaid, StatusPastDue, StatusVoided
LineItemTypeLineItemBase, LineItemUsage, LineItemOverage, LineItemSeat, LineItemDiscount, LineItemTax

Store interface:

type Store interface {
    Create(ctx context.Context, inv *Invoice) error
    Get(ctx context.Context, invID id.InvoiceID) (*Invoice, error)
    List(ctx context.Context, tenantID, appID string, opts ListOpts) ([]*Invoice, error)
    Update(ctx context.Context, inv *Invoice) error
    GetByPeriod(ctx context.Context, tenantID, appID string, periodStart, periodEnd time.Time) (*Invoice, error)
    ListPending(ctx context.Context, appID string) ([]*Invoice, error)
    MarkPaid(ctx context.Context, invID id.InvoiceID, paidAt time.Time, paymentRef string) error
    MarkVoided(ctx context.Context, invID id.InvoiceID, reason string) error
}

type ListOpts struct {
    Status Status
    Start  time.Time
    End    time.Time
    Limit  int
    Offset int
}

See Invoicing for usage details.


github.com/xraph/ledger/coupon

Discounts and promotional codes. Coupons can be percentage-based or fixed-amount, with optional validity windows and redemption limits.

type Coupon struct {
    types.Entity
    ID             id.CouponID
    Code           string
    Name           string
    Type           CouponType        // "percentage" or "amount"
    Amount         types.Money       // For fixed-amount coupons
    Percentage     int               // For percentage coupons (0-100)
    Currency       string
    MaxRedemptions int
    TimesRedeemed  int
    ValidFrom      *time.Time
    ValidUntil     *time.Time
    AppID          string
    Metadata       map[string]string
}

Constants:

ConstantValue
CouponTypePercentage"percentage"
CouponTypeAmount"amount"

Store interface:

type Store interface {
    Create(ctx context.Context, c *Coupon) error
    Get(ctx context.Context, code string, appID string) (*Coupon, error)
    GetByID(ctx context.Context, couponID id.CouponID) (*Coupon, error)
    List(ctx context.Context, appID string, opts ListOpts) ([]*Coupon, error)
    Update(ctx context.Context, c *Coupon) error
    Delete(ctx context.Context, couponID id.CouponID) error
}

type ListOpts struct {
    Active bool
    Limit  int
    Offset int
}

See Coupons for usage details.


github.com/xraph/ledger/types

Shared types used across all Ledger packages.

Money:

type Money struct {
    Amount   int64  // Smallest currency unit (cents, pence, etc.)
    Currency string // ISO 4217 lowercase: "usd", "eur", "gbp"
}

// Constructors
func USD(cents int64) Money
func EUR(cents int64) Money
func GBP(pence int64) Money
func JPY(yen int64) Money
func CAD(cents int64) Money
func AUD(cents int64) Money
func Zero(currency string) Money
func Sum(values ...Money) Money

// Arithmetic (panics on currency mismatch)
func (m Money) Add(other Money) Money
func (m Money) Subtract(other Money) Money
func (m Money) Multiply(qty int64) Money
func (m Money) Divide(divisor int64) Money
func (m Money) Negate() Money
func (m Money) Abs() Money

// Comparison
func (m Money) IsZero() bool
func (m Money) IsPositive() bool
func (m Money) IsNegative() bool
func (m Money) Equal(other Money) bool
func (m Money) LessThan(other Money) bool
func (m Money) GreaterThan(other Money) bool
func (m Money) Min(other Money) Money
func (m Money) Max(other Money) Money

// Formatting
func (m Money) FormatMajor() string  // "49.00"
func (m Money) String() string       // "$49.00"
func (m Money) MarshalJSON() ([]byte, error)

Entity:

type Entity struct {
    CreatedAt time.Time
    UpdatedAt time.Time
}

func NewEntity() Entity
func (e *Entity) Touch()
func (e Entity) Age() time.Duration
func (e Entity) LastModified() time.Duration
func (e Entity) IsNew() bool
func (e Entity) IsStale(staleDuration time.Duration) bool

github.com/xraph/ledger/id

TypeID-based identifiers for all Ledger entities. Every ID is type-prefixed, K-sortable, and UUIDv7-based. IDs are validated at parse time to ensure the prefix matches the expected type.

ID types:

TypePrefixExample
PlanIDplanplan_01h2xcejqtf2nbrexx3vqjhp41
FeatureIDfeatfeat_01h2xcejqtf2nbrexx3vqjhp41
PriceIDpriceprice_01h2xcejqtf2nbrexx3vqjhp41
SubscriptionIDsubsub_01h2xcejqtf2nbrexx3vqjhp41
UsageEventIDuevtuevt_01h2xcejqtf2nbrexx3vqjhp41
EntitlementIDentent_01h2xcejqtf2nbrexx3vqjhp41
InvoiceIDinvinv_01h455vb4pex5vsknk084sn02q
LineItemIDlili_01h455vb4pex5vsknk084sn02q
CouponIDcpncpn_01h455vb4pex5vsknk084sn02q
PaymentIDpaypay_01h455vb4pex5vsknk084sn02q
AnyIDanyAccepts any valid prefix

Constructors:

func NewPlanID() PlanID
func NewFeatureID() FeatureID
func NewPriceID() PriceID
func NewSubscriptionID() SubscriptionID
func NewUsageEventID() UsageEventID
func NewEntitlementID() EntitlementID
func NewInvoiceID() InvoiceID
func NewLineItemID() LineItemID
func NewCouponID() CouponID
func NewPaymentID() PaymentID

Parsers (validate prefix at parse time):

func ParsePlanID(s string) (PlanID, error)
func ParseFeatureID(s string) (FeatureID, error)
func ParsePriceID(s string) (PriceID, error)
func ParseSubscriptionID(s string) (SubscriptionID, error)
func ParseUsageEventID(s string) (UsageEventID, error)
func ParseEntitlementID(s string) (EntitlementID, error)
func ParseInvoiceID(s string) (InvoiceID, error)
func ParseLineItemID(s string) (LineItemID, error)
func ParseCouponID(s string) (CouponID, error)
func ParsePaymentID(s string) (PaymentID, error)
func ParseAny(s string) (AnyID, error)

All IDs implement String() string and are K-sortable (chronological ordering without timestamps).

See Identity for the design rationale.


Store packages

github.com/xraph/ledger/store

The unified storage interface for all Ledger entities. The Store interface explicitly declares all methods from the sub-store interfaces to avoid naming conflicts.

type Store interface {
    // Plan methods (7)
    CreatePlan(ctx context.Context, p *plan.Plan) error
    GetPlan(ctx context.Context, planID id.PlanID) (*plan.Plan, error)
    GetPlanBySlug(ctx context.Context, slug string, appID string) (*plan.Plan, error)
    ListPlans(ctx context.Context, appID string, opts plan.ListOpts) ([]*plan.Plan, error)
    UpdatePlan(ctx context.Context, p *plan.Plan) error
    DeletePlan(ctx context.Context, planID id.PlanID) error
    ArchivePlan(ctx context.Context, planID id.PlanID) error

    // Subscription methods (6)
    CreateSubscription(ctx context.Context, s *subscription.Subscription) error
    GetSubscription(ctx context.Context, subID id.SubscriptionID) (*subscription.Subscription, error)
    GetActiveSubscription(ctx context.Context, tenantID string, appID string) (*subscription.Subscription, error)
    ListSubscriptions(ctx context.Context, tenantID string, appID string, opts subscription.ListOpts) ([]*subscription.Subscription, error)
    UpdateSubscription(ctx context.Context, s *subscription.Subscription) error
    CancelSubscription(ctx context.Context, subID id.SubscriptionID, cancelAt time.Time) error

    // Meter methods (5)
    IngestBatch(ctx context.Context, events []*meter.UsageEvent) error
    Aggregate(ctx context.Context, tenantID, appID, featureKey string, period plan.Period) (int64, error)
    AggregateMulti(ctx context.Context, tenantID, appID string, featureKeys []string, period plan.Period) (map[string]int64, error)
    QueryUsage(ctx context.Context, tenantID, appID string, opts meter.QueryOpts) ([]*meter.UsageEvent, error)
    PurgeUsage(ctx context.Context, before time.Time) (int64, error)

    // Entitlement methods (4)
    GetCached(ctx context.Context, tenantID, appID, featureKey string) (*entitlement.Result, error)
    SetCached(ctx context.Context, tenantID, appID, featureKey string, result *entitlement.Result, ttl time.Duration) error
    Invalidate(ctx context.Context, tenantID, appID string) error
    InvalidateFeature(ctx context.Context, tenantID, appID, featureKey string) error

    // Invoice methods (8)
    CreateInvoice(ctx context.Context, inv *invoice.Invoice) error
    GetInvoice(ctx context.Context, invID id.InvoiceID) (*invoice.Invoice, error)
    ListInvoices(ctx context.Context, tenantID, appID string, opts invoice.ListOpts) ([]*invoice.Invoice, error)
    UpdateInvoice(ctx context.Context, inv *invoice.Invoice) error
    GetInvoiceByPeriod(ctx context.Context, tenantID, appID string, periodStart, periodEnd time.Time) (*invoice.Invoice, error)
    ListPendingInvoices(ctx context.Context, appID string) ([]*invoice.Invoice, error)
    MarkInvoicePaid(ctx context.Context, invID id.InvoiceID, paidAt time.Time, paymentRef string) error
    MarkInvoiceVoided(ctx context.Context, invID id.InvoiceID, reason string) error

    // Coupon methods (6)
    CreateCoupon(ctx context.Context, c *coupon.Coupon) error
    GetCoupon(ctx context.Context, code string, appID string) (*coupon.Coupon, error)
    GetCouponByID(ctx context.Context, couponID id.CouponID) (*coupon.Coupon, error)
    ListCoupons(ctx context.Context, appID string, opts coupon.ListOpts) ([]*coupon.Coupon, error)
    UpdateCoupon(ctx context.Context, c *coupon.Coupon) error
    DeleteCoupon(ctx context.Context, couponID id.CouponID) error

    // Core methods (3)
    Migrate(ctx context.Context) error
    Ping(ctx context.Context) error
    Close() error
}

See Custom Store for implementing your own store.


github.com/xraph/ledger/store/memory

In-memory store implementation for testing and development. All data is stored in Go maps with sync.RWMutex for thread safety.

func New() *Store

The memory store implements the full store.Store interface. No configuration is needed. Data is lost when the process exits.

import "github.com/xraph/ledger/store/memory"

s := memory.New()
l := ledger.New(s)

See Memory Store for details.


github.com/xraph/ledger/store/postgres

PostgreSQL store implementation for production use. Uses bun ORM for database operations with automatic migrations.

func New(databaseURL string) (*Store, error)
import "github.com/xraph/ledger/store/postgres"

s, err := postgres.New("postgres://user:pass@localhost:5432/ledger?sslmode=disable")
if err != nil {
    log.Fatal(err)
}

See PostgreSQL Store for configuration and schema details.


Plugin packages

github.com/xraph/ledger/plugin

Plugin system and registry. Plugins implement lifecycle hooks to extend Ledger's functionality. The base Plugin interface requires only a Name() method; hook interfaces are optional and implement-any-subset.

Base interface:

type Plugin interface {
    Name() string
}

Lifecycle hooks:

InterfaceMethod signatureTrigger
OnInitOnInit(ctx, ledger interface{}) errorEngine started
OnShutdownOnShutdown(ctx) errorEngine stopping

Plan hooks:

InterfaceMethod signatureTrigger
OnPlanCreatedOnPlanCreated(ctx, plan interface{}) errorPlan created
OnPlanUpdatedOnPlanUpdated(ctx, oldPlan, newPlan interface{}) errorPlan updated
OnPlanArchivedOnPlanArchived(ctx, planID string) errorPlan archived

Subscription hooks:

InterfaceMethod signatureTrigger
OnSubscriptionCreatedOnSubscriptionCreated(ctx, sub interface{}) errorSubscription created
OnSubscriptionChangedOnSubscriptionChanged(ctx, sub, oldPlan, newPlan interface{}) errorPlan changed
OnSubscriptionCanceledOnSubscriptionCanceled(ctx, sub interface{}) errorSubscription canceled
OnSubscriptionExpiredOnSubscriptionExpired(ctx, sub interface{}) errorSubscription expired

Usage/Metering hooks:

InterfaceMethod signatureTrigger
OnUsageIngestedOnUsageIngested(ctx, events []interface{}) errorEvents ingested
OnUsageFlushedOnUsageFlushed(ctx, count int, elapsed time.Duration) errorBatch flushed to store

Entitlement hooks:

InterfaceMethod signatureTrigger
OnEntitlementCheckedOnEntitlementChecked(ctx, result interface{}) errorEntitlement checked
OnQuotaExceededOnQuotaExceeded(ctx, tenantID, featureKey string, used, limit int64) errorHard quota exceeded
OnSoftLimitReachedOnSoftLimitReached(ctx, tenantID, featureKey string, used, limit int64) errorSoft limit reached

Invoice hooks:

InterfaceMethod signatureTrigger
OnInvoiceGeneratedOnInvoiceGenerated(ctx, inv interface{}) errorInvoice generated
OnInvoiceFinalizedOnInvoiceFinalized(ctx, inv interface{}) errorInvoice finalized
OnInvoicePaidOnInvoicePaid(ctx, inv interface{}) errorInvoice paid
OnInvoiceFailedOnInvoiceFailed(ctx, inv interface{}, err error) errorPayment failed
OnInvoiceVoidedOnInvoiceVoided(ctx, inv interface{}, reason string) errorInvoice voided

Provider hooks:

InterfaceMethod signatureTrigger
OnProviderSyncOnProviderSync(ctx, provider string, success bool, err error) errorProvider sync
OnWebhookReceivedOnWebhookReceived(ctx, provider string, payload []byte) errorWebhook received
PaymentProviderPluginProvider() interface{}Provides payment provider

Strategy plugins:

InterfaceKey methodPurpose
PricingStrategyCompute(tiers, usage, included, currency)Custom pricing calculation
UsageAggregatorAggregate(ctx, events)Custom usage aggregation
TaxCalculatorCalculateTax(ctx, subtotal, tenantID)Tax computation
InvoiceFormatterRender(ctx, inv, writer)Invoice export (PDF, HTML, CSV)
CouponValidatorValidateCoupon(ctx, coupon, sub)Custom coupon validation

Registry:

func NewRegistry() *Registry
func (r *Registry) Register(p Plugin) error
func (r *Registry) Get(name string) Plugin
func (r *Registry) List() []Plugin
func (r *Registry) Count() int
func (r *Registry) WithLogger(logger *slog.Logger) *Registry

// Strategy lookups
func (r *Registry) GetPaymentProviders() []PaymentProviderPlugin
func (r *Registry) GetPricingStrategy(name string) PricingStrategy
func (r *Registry) GetTaxCalculators() []TaxCalculator

The registry uses type-cached discovery for O(1) dispatch performance. All hook calls include a 5-second timeout to prevent plugins from blocking the billing pipeline.

See Custom Plugin for writing custom plugins.


Extension packages

github.com/xraph/ledger/observability

Metrics extension that records lifecycle event counts via a MetricFactory interface. Registers counters and histograms for all major billing operations.

func NewMetricsExtension(factory MetricFactory) *MetricsExtension

MetricFactory interface:

type MetricFactory interface {
    Counter(name string) Counter
    Histogram(name string) Histogram
}

type Counter interface {
    Inc()
    Add(float64)
}

type Histogram interface {
    Observe(float64)
}

Recorded metrics:

MetricTypeDescription
ledger.plan.createdCounterPlans created
ledger.plan.updatedCounterPlans updated
ledger.plan.archivedCounterPlans archived
ledger.subscription.createdCounterSubscriptions created
ledger.subscription.upgradedCounterPlan upgrades
ledger.subscription.downgradedCounterPlan downgrades
ledger.subscription.canceledCounterCancellations
ledger.subscription.expiredCounterExpirations
ledger.usage.events.ingestedCounterUsage events ingested
ledger.usage.batch.sizeHistogramBatch sizes
ledger.usage.flush.latency_msHistogramFlush latency in ms
ledger.entitlement.checksCounterEntitlement checks
ledger.entitlement.cache.hitsCounterCache hits
ledger.entitlement.cache.missesCounterCache misses
ledger.entitlement.deniedCounterAccess denied
ledger.entitlement.latency_msHistogramCheck latency in ms
ledger.invoice.generatedCounterInvoices generated
ledger.invoice.finalizedCounterInvoices finalized
ledger.invoice.paidCounterInvoices paid
ledger.invoice.voidedCounterInvoices voided
ledger.invoice.total_amountHistogramInvoice amounts
ledger.provider.sync.successCounterSuccessful syncs
ledger.provider.sync.failureCounterFailed syncs
ledger.webhook.receivedCounterWebhooks received
ledger.webhook.processedCounterWebhooks processed
ledger.store.errorsCounterStore errors
ledger.plugin.errorsCounterPlugin errors

See Custom Plugin for integration details.


github.com/xraph/ledger/audit_hook

Audit trail extension that bridges Ledger lifecycle events to an audit backend. Uses a local Recorder interface so the package does not import Chronicle directly.

func New(r Recorder, opts ...Option) *Extension

Recorder interface:

type Recorder interface {
    Record(ctx context.Context, event *AuditEvent) error
}

// Adapter for plain functions
type RecorderFunc func(ctx context.Context, event *AuditEvent) error

type AuditEvent struct {
    Action     string
    Resource   string
    Category   string
    ResourceID string
    Metadata   map[string]any
    Outcome    string
    Severity   string
    Reason     string
}

Options:

OptionDescription
WithLogger(*slog.Logger)Set the logger
WithEnabledActions(actions ...string)Audit only these actions (whitelist)
WithDisabledActions(actions ...string)Skip these actions (blacklist)

Action constants:

ConstantValue
ActionPlanCreated"plan.created"
ActionPlanUpdated"plan.updated"
ActionPlanArchived"plan.archived"
ActionSubscriptionCreated"subscription.created"
ActionSubscriptionUpgraded"subscription.upgraded"
ActionSubscriptionDowngraded"subscription.downgraded"
ActionSubscriptionCanceled"subscription.canceled"
ActionSubscriptionExpired"subscription.expired"
ActionUsageIngested"usage.ingested"
ActionUsageFlushed"usage.flushed"
ActionEntitlementChecked"entitlement.checked"
ActionEntitlementDenied"entitlement.denied"
ActionQuotaExceeded"quota.exceeded"
ActionSoftLimitReached"soft_limit.reached"
ActionInvoiceGenerated"invoice.generated"
ActionInvoiceFinalized"invoice.finalized"
ActionInvoicePaid"invoice.paid"
ActionInvoiceFailed"invoice.failed"
ActionInvoiceVoided"invoice.voided"
ActionProviderSync"provider.sync"
ActionWebhookReceived"webhook.received"
ActionWebhookProcessed"webhook.processed"

Resource, Category, Severity, and Outcome constants:

// Resources
ResourcePlan, ResourceSubscription, ResourceUsage,
ResourceEntitlement, ResourceInvoice, ResourceProvider, ResourceWebhook

// Categories
CategoryBilling, CategorySubscription, CategoryUsage,
CategoryAccess, CategoryPayment, CategoryIntegration

// Severities
SeverityInfo, SeverityWarning, SeverityError, SeverityCritical

// Outcomes
OutcomeSuccess, OutcomeFailure, OutcomePartial

See Custom Plugin for integration details.


Package index

PackageImport pathPurpose
ledgergithub.com/xraph/ledgerMain engine and configuration
plangithub.com/xraph/ledger/planPlan and feature definitions
subscriptiongithub.com/xraph/ledger/subscriptionSubscription lifecycle management
metergithub.com/xraph/ledger/meterUsage event tracking and batching
entitlementgithub.com/xraph/ledger/entitlementFeature access checking with cache
invoicegithub.com/xraph/ledger/invoiceInvoice generation and line items
coupongithub.com/xraph/ledger/couponDiscounts and promotional codes
typesgithub.com/xraph/ledger/typesMoney, Entity, and common types
idgithub.com/xraph/ledger/idTypeID identifiers
storegithub.com/xraph/ledger/storeUnified storage interface
store/memorygithub.com/xraph/ledger/store/memoryIn-memory store for testing
store/postgresgithub.com/xraph/ledger/store/postgresPostgreSQL implementation
plugingithub.com/xraph/ledger/pluginPlugin system and registry
audit_hookgithub.com/xraph/ledger/audit_hookAudit trail extension
observabilitygithub.com/xraph/ledger/observabilityMetrics extension

On this page