Documentation
¶
Index ¶
- Constants
- type AccountSubscriptionInfo
- type AccountUsage
- type AccountUsageRepo
- type AgentTokenBilling
- type AgentTokenBillingRepo
- type BillingIntentAction
- type BillingIntentCommitResult
- type BillingIntentLineItem
- type BillingIntentReservation
- type BillingProfileResult
- type BillingSvc
- type ComponentConfiguration
- type CoreClient
- type EnsureBillingCustomerResult
- type ErrBillingIntentConflict
- type IdempotencyKey
- type IdempotencyKeyRepo
- type IdempotencyMed
- type ListPricingPlansInput
- type ListPricingPlansResult
- type NotificationClient
- type PlanChangePreview
- type PlanChangePreviewLineItem
- type PlanLimit
- type PricingPlan
- type PricingPlanRepo
- type ProcessWebhookEventInput
- type ProcessWebhookEventResult
- type RecoveryPoint
- type RepoFactory
- type RequestEnterpriseUpgradeInput
- type RequestEnterpriseUpgradeResult
- type SetupIntentResult
- type StripeBillingPortalSession
- type StripeClient
- type StripeCustomer
- type StripeEvent
- type StripePricingPlan
- type StripeSetupIntent
- type StripeWebhookSvc
- type SubscriptionInfoResult
- type SwitchPlanResult
- type TokenRate
- type UpsertAgentTokenBillingParams
- type UsageItem
Constants ¶
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 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 ¶
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 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 ¶
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 ErrBillingIntentConflict ¶
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 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 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 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 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 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 SwitchPlanResult ¶
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.
Source Files
¶
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. |