domain

package
v1.4.2 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ServiceName = "billing-service"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AccountSubscriptionInfo

type AccountSubscriptionInfo struct {
	SubscriptionStatus           *string
	SubscriptionCurrentPeriodEnd *time.Time
	StripeSubscriptionID         *string
	ServicingStatus              *string
	CollectionStatus             *string
	BillingProfileID             *string
	BillingCadenceID             *string
	PricingPlanSubscriptionID    *string
}

func (*AccountSubscriptionInfo) PeriodEnd

func (i *AccountSubscriptionInfo) PeriodEnd() *time.Time

Returns the subscription's current period end, or nil when the account has no subscription at all.

type AccountUsage

type AccountUsage struct {
	Seats                    UsageItem
	Invoices                 UsageItem
	Batches                  UsageItem
	Sandboxes                UsageItem
	Subscription             *SubscriptionInfoResult
	EstimatedAgentSpendCents int64
	// PlanName is the pricing plan's display name resolved live from Stripe; empty when the account has no Stripe pricing plan.
	PlanName string
	// BaseFeeCents is the flat base fee charged per BaseFeeInterval, resolved from the plan's license fee component; 0 when the plan has no base fee.
	BaseFeeCents int64
	// BaseFeeInterval is the interval the base fee is charged on (e.g. "month"); empty when there is no base fee.
	BaseFeeInterval string
}

type AccountUsageRepo

type AccountUsageRepo interface {
	GetLimitsByAccountID(ctx context.Context, accountID string) ([]PlanLimit, *apierror.APIError)
	CountUsersByAccountID(ctx context.Context, accountID string) (int, *apierror.APIError)
	CountSandboxesByAccountID(ctx context.Context, accountID string) (int, *apierror.APIError)
	CountInvoicesByAccountID(ctx context.Context, accountID string, periodStart time.Time) (int, *apierror.APIError)
	CountBatchesByAccountID(ctx context.Context, accountID string, periodStart time.Time) (int, *apierror.APIError)
	GetAccountSubscriptionInfo(ctx context.Context, accountID string) (*AccountSubscriptionInfo, *apierror.APIError)
	GetStripeCustomerIDByAccountID(ctx context.Context, accountID string) (*string, *apierror.APIError)
	GetAccountNameAndPlanCode(ctx context.Context, accountID string) (name string, planCode string, apiErr *apierror.APIError)
	// GetAccountStripePricingPlanID returns the Stripe pricing plan id (bpp_...) attached to the account's current plan, or nil when the plan has none (e.g. free). Resolved from the account's actual plan row so it stays correct when several plans share a plan_type_code.
	GetAccountStripePricingPlanID(ctx context.Context, accountID string) (*string, *apierror.APIError)
	GetUserEmailByID(ctx context.Context, userID string) (email string, displayName *string, apiErr *apierror.APIError)
	GetAdminEmailByAccountID(ctx context.Context, accountID string) (string, *apierror.APIError)
	UpdateStripeCustomerIDByAccountID(ctx context.Context, stripeCustomerID, accountID string) *apierror.APIError
}

type AgentTokenBilling

type AgentTokenBilling struct {
	ID                     string
	AccountID              string
	PeriodStart            time.Time
	PeriodEnd              time.Time
	TotalInputTokens       int64
	TotalOutputTokens      int64
	TotalTokens            int64
	TokensReportedToStripe int64
	StripeMeteredItemID    *string
	RunCount               int
	CreatedAt              time.Time
	UpdatedAt              time.Time
}

type AgentTokenBillingRepo

type AgentTokenBillingRepo interface {
	UpsertAgentTokenBilling(ctx context.Context, params UpsertAgentTokenBillingParams) *apierror.APIError
	GetByAccountAndPeriod(ctx context.Context, accountID string, periodStart time.Time) (*AgentTokenBilling, *apierror.APIError)
	GetUsageSummary(ctx context.Context, accountID string, periodStart time.Time) (int64, *apierror.APIError)
	GetCompletedTokensByAccount(ctx context.Context, accountID string) (int64, *apierror.APIError)
}

type BillingIntentAction

type BillingIntentAction struct {
	Type                    string // "subscribe", "modify", "deactivate"
	PricingPlanID           string
	PricingPlanVersion      string
	SubscriptionID          string // for modify/deactivate
	ComponentConfigurations []ComponentConfiguration
}

BillingIntentAction represents an action in a billing intent (subscribe, modify, deactivate).

type BillingIntentCommitResult

type BillingIntentCommitResult struct {
	PricingPlanSubscriptionIDs []string
}

BillingIntentCommitResult holds IDs extracted from a committed billing intent.

type BillingIntentLineItem

type BillingIntentLineItem struct {
	Description string
	Amount      int64
}

BillingIntentLineItem represents a line item from a billing intent reservation.

type BillingIntentReservation

type BillingIntentReservation struct {
	IntentID  string
	NetAmount int64
	LineItems []BillingIntentLineItem
}

BillingIntentReservation holds the result of reserving a billing intent.

type BillingProfileResult

type BillingProfileResult struct {
	ProfileID string
	CadenceID string
}

type BillingSvc

type BillingSvc interface {
	// ListPricingPlans returns a paginated list of currently active pricing plans with their limits and features.
	ListPricingPlans(ctx context.Context, input ListPricingPlansInput) (*ListPricingPlansResult, *apierror.APIError)

	// GetPlanByCode returns a single pricing plan by its plan type code.
	GetPlanByCode(ctx context.Context, planCode string) (*PricingPlan, *apierror.APIError)

	// GetAccountUsage returns current resource usage for the given account with plan limits and subscription information.
	GetAccountUsage(ctx context.Context, accountID string) (*AccountUsage, *apierror.APIError)

	// GetAgentSpendCents returns the marked-up token spend the account has accrued this billing period, as it will be billed in Stripe. This is the same figure surfaced on the dashboard; agent-service uses it to enforce the spending cap consistently.
	GetAgentSpendCents(ctx context.Context, accountID string) (int64, *apierror.APIError)

	// GetAgentTokenRates returns the marked-up per-token rates from the account's plan rate card, so agent-service can price a run's in-flight usage against the cap with the same rates Stripe bills (no per-turn round trip). Empty when the account has no pricing plan or rate card.
	GetAgentTokenRates(ctx context.Context, accountID string) ([]TokenRate, *apierror.APIError)

	// CreateBillingPortalSession creates a Stripe billing portal session for managing subscriptions. Returns the portal URL.
	CreateBillingPortalSession(ctx context.Context, accountID string) (string, *apierror.APIError)

	// PreviewPlanChange previews the cost impact of switching to a different pricing plan using the billing intent reserve+void pattern.
	PreviewPlanChange(ctx context.Context, accountID string, planID string) (*PlanChangePreview, *apierror.APIError)

	// RequestEnterpriseUpgrade sends an enterprise plan inquiry to support on behalf of the requesting admin.
	RequestEnterpriseUpgrade(ctx context.Context, input RequestEnterpriseUpgradeInput) (*RequestEnterpriseUpgradeResult, *apierror.APIError)

	// EnsureBillingCustomer links or fetches a Stripe customer for an account. If one already exists it is returned; otherwise a new one is created. Also creates a billing profile if one doesn't exist.
	EnsureBillingCustomer(ctx context.Context, accountID string) (*EnsureBillingCustomerResult, *apierror.APIError)

	// CreateRegistrationCustomer creates a Stripe customer for a registration session before an account exists. Uses the provided email/name directly.
	CreateRegistrationCustomer(ctx context.Context, email, name, idempotencyKey string, metadata map[string]string) (*EnsureBillingCustomerResult, *apierror.APIError)

	// SwitchPlan initiates a plan switch using v2 billing intents.
	SwitchPlan(ctx context.Context, accountID string, planID string) (*SwitchPlanResult, *apierror.APIError)

	// SetupBillingProfile creates a billing profile and cadence for an account.
	SetupBillingProfile(ctx context.Context, accountID string) (*BillingProfileResult, *apierror.APIError)

	// SubscribeToPricingPlan subscribes a Stripe customer to a v2 pricing plan.
	SubscribeToPricingPlan(ctx context.Context, stripeCustomerID, planCode string) *apierror.APIError

	// CreateSetupIntent creates a Stripe Setup Intent for collecting a payment method.
	CreateSetupIntent(ctx context.Context, customerID, idempotencyKey string) (*SetupIntentResult, *apierror.APIError)

	// GetSetupIntentStatus returns the current status of a Stripe Setup Intent.
	GetSetupIntentStatus(ctx context.Context, setupIntentID string) (*SetupIntentResult, *apierror.APIError)

	// ValidateStripePricingPlan checks whether the Stripe pricing plan for a given plan code is accessible. Returns nil if valid or free plan.
	ValidateStripePricingPlan(ctx context.Context, planCode string) *apierror.APIError
}

type ComponentConfiguration

type ComponentConfiguration struct {
	PricingPlanComponentID string
	Quantity               int
}

ComponentConfiguration sets the quantity for a pricing plan component (e.g. license fee seats).

type CoreClient

type CoreClient interface {
	GetAccountByStripeCustomerID(ctx context.Context, stripeCustomerID string) (accountID string, planCode string, apiErr *apierror.APIError)
	UpdateAccountSubscription(ctx context.Context, idempotencyKey, accountID string, status *string, planCode string, stripeSubID *string, periodEnd *time.Time, stripeCustomerID *string, billingProfileID *string, billingCadenceID *string, pricingPlanSubscriptionID *string, servicingStatus *string, collectionStatus *string) *apierror.APIError
	ClearAccountStripeCustomer(ctx context.Context, idempotencyKey, accountID string) *apierror.APIError
}

CoreClient is the interface for calling core-service RPCs from the billing service layer.

type EnsureBillingCustomerResult

type EnsureBillingCustomerResult struct {
	StripeCustomerID string
	Created          bool
	BillingProfileID *string
}

type ErrBillingIntentConflict

type ErrBillingIntentConflict struct {
	ConflictingIntentID string
	Err                 error
}

ErrBillingIntentConflict is returned when CreateBillingIntent fails because a pricing plan subscription is already reserved by another billing intent.

func (*ErrBillingIntentConflict) Error

func (e *ErrBillingIntentConflict) Error() string

func (*ErrBillingIntentConflict) Unwrap

func (e *ErrBillingIntentConflict) Unwrap() error

type IdempotencyKey

type IdempotencyKey struct {
	ID             int64
	TypeID         string
	ServiceName    string
	Handler        string
	IdempotencyKey string
	ActorID        *string
	IdentityType   string
	ScopeHash      string
	ResponseCode   *int
	ResponseBody   json.RawMessage
	RecoveryPoint  string
}

func (*IdempotencyKey) HasResponse

func (k *IdempotencyKey) HasResponse() bool

func (*IdempotencyKey) IsFinished

func (k *IdempotencyKey) IsFinished() bool

type IdempotencyKeyRepo

type IdempotencyKeyRepo interface {
	GetByScopeHash(ctx context.Context, scopeHash string) (*IdempotencyKey, *apierror.APIError)
	Create(ctx context.Context, key *IdempotencyKey) (*IdempotencyKey, *apierror.APIError)
	AdvanceRecoveryPoint(ctx context.Context, typeID string, recoveryPoint RecoveryPoint) *apierror.APIError
	GetRecoveryPoint(ctx context.Context, typeID string) (RecoveryPoint, *apierror.APIError)
	SetResponse(ctx context.Context, typeID string, code int, body json.RawMessage, recoveryPoint RecoveryPoint) *apierror.APIError
}

type IdempotencyMed

type IdempotencyMed interface {
	// UpsertIdempotencyKey returns the existing idempotency key for the request scope, or creates one if it does not exist.
	//
	//  1. Resolve the idempotency key from the request context, falling back to the request ID.
	//  2. Compute the scope hash from the actor, target account, service, handler, and key.
	//  3. Return the existing key for the scope hash when one exists.
	//  4. Otherwise persist a new key at the Started recovery point, re-fetching the
	//     existing row if a concurrent request inserted the same scope hash first.
	UpsertIdempotencyKey(ctx context.Context, identity *types.Identity) (*IdempotencyKey, *apierror.APIError)

	// CacheErrorResponse caches a non-transient error response for the given idempotency key and returns the original error.
	//
	//  1. Return transient errors uncached so the client can retry.
	//  2. Persist non-transient errors as the cached response and mark the key finished.
	CacheErrorResponse(ctx context.Context, typeID string, apiErr *apierror.APIError) *apierror.APIError

	// CacheSuccessResponse caches a successful response for the given idempotency key.
	//
	//  1. Marshal the response data to JSON.
	//  2. Persist it as the cached response and mark the key finished.
	CacheSuccessResponse(ctx context.Context, typeID string, data any) *apierror.APIError
}

type ListPricingPlansInput

type ListPricingPlansInput struct {
	Cursor *string
	Limit  int32
	Query  *string
}

type ListPricingPlansResult

type ListPricingPlansResult struct {
	Plans    []PricingPlan
	PageInfo pagination.PageInfo
}

type NotificationClient

type NotificationClient interface {
	SendEnterpriseRequest(ctx context.Context, accountID, accountName, currentPlanName, requesterName, requesterEmail string) *apierror.APIError
	SendPaymentActionRequired(ctx context.Context, accountID, adminEmail string) *apierror.APIError
}

NotificationClient is the interface for calling notification-service RPCs.

type PlanChangePreview

type PlanChangePreview struct {
	NetAmount                  int64
	FormattedNetAmount         string
	MonthlyBillAmount          int64
	FormattedMonthlyBillAmount string
	LineItems                  []PlanChangePreviewLineItem
	IsEstimate                 bool
}

type PlanChangePreviewLineItem

type PlanChangePreviewLineItem struct {
	Description string
	Amount      int64
}

type PlanLimit

type PlanLimit struct {
	Key   string
	Value *int
}

type PricingPlan

type PricingPlan struct {
	ID                   int64
	CreatedAt            time.Time
	TypeID               string
	Name                 string
	PlanTypeCode         string
	PricePerSeat         float64
	PricePerMonth        *float64
	SeatMinimum          *int
	Limits               []PlanLimit
	DisplayFeatures      []string
	DisplayOrder         int
	IsHighlighted        bool
	ButtonText           string
	IncludesPreviousPlan *string
	StripePricingPlanID  *string
}

type PricingPlanRepo

type PricingPlanRepo interface {
	GetPlanByCode(ctx context.Context, planCode string) (*PricingPlan, *apierror.APIError)
	GetPlanByTypeID(ctx context.Context, typeID string) (*PricingPlan, *apierror.APIError)
	GetPlanLimitsByTypeID(ctx context.Context, typeID string) ([]PlanLimit, *apierror.APIError)
	ListPricingPlans(ctx context.Context, cursor *string, limit int32, query *string) ([]PricingPlan, pagination.PageInfo, *apierror.APIError)
}

type ProcessWebhookEventInput

type ProcessWebhookEventInput struct {
	RawPayload      []byte
	StripeSignature string
}

type ProcessWebhookEventResult

type ProcessWebhookEventResult struct {
	Success bool
}

type RecoveryPoint

type RecoveryPoint string
const (
	RecoveryPointStarted         RecoveryPoint = "billing:started"
	RecoveryPointProfileCreated  RecoveryPoint = "billing:profile_created"
	RecoveryPointIntentCommitted RecoveryPoint = "billing:intent_committed"
	RecoveryPointFinished        RecoveryPoint = "billing:finished"
)

func (RecoveryPoint) IsValid

func (r RecoveryPoint) IsValid() bool

func (RecoveryPoint) String

func (r RecoveryPoint) String() string

type RepoFactory

type RepoFactory interface {
	NewPricingPlanRepo() PricingPlanRepo
	NewAccountUsageRepo() AccountUsageRepo
	NewAgentTokenBillingRepo() AgentTokenBillingRepo
	NewIdempotencyKeyRepo() IdempotencyKeyRepo
	NewOutboxRepo() messaging.OutboxRepo
}

type RequestEnterpriseUpgradeInput

type RequestEnterpriseUpgradeInput struct {
	AccountID string
	ActorID   string
	ActorName string
}

type RequestEnterpriseUpgradeResult

type RequestEnterpriseUpgradeResult struct {
	Success bool
}

type SetupIntentResult

type SetupIntentResult struct {
	SetupIntentID   string
	ClientSecret    string // #nosec G117 -- Stripe ephemeral client secret
	Status          string
	PaymentMethodID *string
}

SetupIntentResult holds the result of a Setup Intent operation.

type StripeBillingPortalSession

type StripeBillingPortalSession struct {
	URL string
}

StripeBillingPortalSession represents a created Stripe billing portal session.

type StripeClient

type StripeClient interface {
	// V1 APIs (still needed)
	VerifyWebhookSignature(payload []byte, signature string) (*StripeEvent, error)
	CreateCustomer(ctx context.Context, email, name, idempotencyKey string, metadata map[string]string) (*StripeCustomer, error)
	CreateBillingPortalSession(ctx context.Context, customerID, returnURL string) (*StripeBillingPortalSession, error)

	// V2 Pricing Plan APIs
	GetPricingPlan(ctx context.Context, pricingPlanID string) (*StripePricingPlan, error)
	CreateBillingProfile(ctx context.Context, customerID, idempotencyKey string) (profileID string, err error)
	CreateBillingCadence(ctx context.Context, billingProfileID, idempotencyKey string) (cadenceID string, err error)
	CreateBillingIntent(ctx context.Context, cadenceID string, actions []BillingIntentAction, idempotencyKey string) (intentID string, err error)
	ReserveBillingIntent(ctx context.Context, intentID string) (*BillingIntentReservation, error)
	CreatePaymentIntent(ctx context.Context, amountCents int64, currency, customerID, returnURL string) (paymentIntentID string, err error)
	CommitBillingIntent(ctx context.Context, intentID string, paymentIntentID *string, cadenceID string) (*BillingIntentCommitResult, error)
	VoidBillingIntent(ctx context.Context, intentID string) error

	// FetchObject fetches a Stripe object by its API path (used for v2 thin event related_object).
	FetchObject(ctx context.Context, objectURL string) ([]byte, error)

	// CreateSetupIntent creates a Stripe Setup Intent for collecting a payment method.
	CreateSetupIntent(ctx context.Context, customerID, idempotencyKey string) (*StripeSetupIntent, error)
	// GetSetupIntent retrieves the current state of a Stripe Setup Intent.
	GetSetupIntent(ctx context.Context, setupIntentID string) (*StripeSetupIntent, error)

	// ReportMeterEvent reports a usage meter event to the Stripe V2 billing/meter_events API.
	ReportMeterEvent(ctx context.Context, eventName, stripeCustomerID string, value int, idempotencyKey string) error

	// GetAgentTokenSpendCents returns the marked-up cost in cents of the customer's metered LLM token usage since the given time, reconstructed from the plan's rate card rates and the Stripe usage meter. This equals what Stripe will bill for the metered token lines: rates carry the plan's markup and the AI Gateway meters real per-model, per-token-type usage (including cache). Returns 0 when the rate card has no rates or the customer has no usage in the window.
	GetAgentTokenSpendCents(ctx context.Context, customerID, rateCardID string, since time.Time) (int64, error)

	// GetRateCardTokenRates returns every marked-up per-token rate on a rate card, keyed by (model, token_type). These are the same rates GetAgentTokenSpendCents prices usage against; callers use them to price in-flight usage without a Stripe round trip.
	GetRateCardTokenRates(ctx context.Context, rateCardID string) ([]TokenRate, error)

	// CreateCreditGrant grants prepaid billing credits (amountCents, USD) to a customer for a purchased token pack. The grant is scoped to metered usage and never expires, so it draws down against the plan's LLM-token rate card as agents run. idempotencyKey guards duplicate grants on webhook redelivery. Returns the Stripe credit grant id.
	CreateCreditGrant(ctx context.Context, customerID string, amountCents int64, name, idempotencyKey string) (grantID string, err error)

	// GetCreditGrantBalanceCents returns the customer's available prepaid credit balance in cents, summed across metered-scoped credit grants. Drives the dashboard balance display and the agent runner's prepaid gate; the burndown itself happens inside Stripe.
	GetCreditGrantBalanceCents(ctx context.Context, customerID string) (int64, error)
}

StripeClient is the interface for all Stripe API operations needed by the billing service, including v2 pricing plan billing and customer management.

type StripeCustomer

type StripeCustomer struct {
	ID string
}

StripeCustomer represents a Stripe customer created during registration.

type StripeEvent

type StripeEvent struct {
	ID       string
	Type     string
	ObjectID string
	Data     []byte
}

type StripePricingPlan

type StripePricingPlan struct {
	ID                    string
	LiveVersion           string
	LicenseFeeComponentID string
	// RateCardID is the id (rcd_...) of the rate card component attached to the plan's live version, empty when the plan has no rate card. It prices the plan's metered LLM token usage (markup baked in).
	RateCardID string
	// DisplayName is the plan's human-facing name in Stripe (e.g. "Founder").
	DisplayName string
	// BaseFeeCents is the flat recurring fee in cents from the plan's license fee component, 0 when the plan has none. BaseFeeInterval is the interval it recurs on (e.g. "month").
	BaseFeeCents    int64
	BaseFeeInterval string
}

StripePricingPlan represents a v2 pricing plan with its live version.

type StripeSetupIntent

type StripeSetupIntent struct {
	ID              string
	ClientSecret    string // #nosec G117 -- Stripe ephemeral client secret
	Status          string
	PaymentMethodID *string
}

StripeSetupIntent represents a Stripe Setup Intent for collecting payment methods.

type StripeWebhookSvc

type StripeWebhookSvc interface {
	// ProcessWebhookEvent verifies a Stripe webhook signature and enqueues the event for asynchronous processing via the message outbox.
	ProcessWebhookEvent(ctx context.Context, input ProcessWebhookEventInput) (*ProcessWebhookEventResult, *apierror.APIError)
}

type SubscriptionInfoResult

type SubscriptionInfoResult struct {
	ServicingStatus  string
	CollectionStatus string
}

type SwitchPlanResult

type SwitchPlanResult struct {
	Success  bool
	IntentID *string
}

type TokenRate

type TokenRate struct {
	// Model is the gateway model name the rate applies to (e.g. "anthropic/claude-sonnet-4.6").
	Model string
	// TokenType is the token type the rate applies to: input, output, cached_input, or cached_output.
	TokenType string
	// UnitAmountCents is the price in cents per token, markup included.
	UnitAmountCents float64
}

TokenRate is a marked-up per-token price from a plan's rate card.

type UpsertAgentTokenBillingParams

type UpsertAgentTokenBillingParams struct {
	ID           string
	AccountID    string
	PeriodStart  time.Time
	PeriodEnd    time.Time
	InputTokens  int64
	OutputTokens int64
	TotalTokens  int64
}

type UsageItem

type UsageItem struct {
	Current int
	Limit   *int
}

Directories

Path Synopsis
mock
client
Package clientmock is a generated GoMock package.
Package clientmock is a generated GoMock package.
factory
Package factorymock is a generated GoMock package.
Package factorymock is a generated GoMock package.
mediator
Package mediatormock is a generated GoMock package.
Package mediatormock is a generated GoMock package.
repository
Package repositorymock is a generated GoMock package.
Package repositorymock is a generated GoMock package.
service
Package servicemock is a generated GoMock package.
Package servicemock is a generated GoMock package.

Jump to

Keyboard shortcuts

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